getDescricao(){
return descricao;
}
}
-- AndreChinvelski - 05 Jul 2005
package JogoGeneral;
import JogoGeneral.Jogada.Tipo;
import junit.framework.TestCase;
public class TesteJogada? extends TestCase? {
Jogada jogada;
protected void setUp() throws Exception {
super.setUp();
}
public void testeJogada(){
int[] facesDoDadoSorteadas = new int[5];
facesDoDadoSorteadas[0]=2;
facesDoDadoSorteadas[1]=2;
facesDoDadoSorteadas[2]=2;
facesDoDadoSorteadas[3]=2;
facesDoDadoSorteadas[4]=3;
jogada = new Jogada(facesDoDadoSorteadas);
assertNotNull("Jogada não pode ser null",jogada);
verifiqueNormal();
verifiqueFula();
verifiqueQuadra();
verifiqueFula();
verifiqueQuina();
}
private void verifiqueNormal() {
int[] facesDoDadoSorteadas = new int[5];
facesDoDadoSorteadas[0]=2;
facesDoDadoSorteadas[1]=2;
facesDoDadoSorteadas[2]=4;
facesDoDadoSorteadas[3]=2;
facesDoDadoSorteadas[4]=3;
jogada = new Jogada(facesDoDadoSorteadas);
assert jogada.jogadaEscolhida(Tipo.NORMAL,1):"Número escolhido não existe no conjunto de faces sorteadas";
}
private void verifiqueQuina() {
int[] facesDoDadoSorteadas = new int[5];
facesDoDadoSorteadas[0]=2;
facesDoDadoSorteadas[1]=2;
facesDoDadoSorteadas[2]=2;
facesDoDadoSorteadas[3]=2;
facesDoDadoSorteadas[4]=2;
jogada = new Jogada(facesDoDadoSorteadas);
assert jogada.jogadaEscolhida(Tipo.QUINA,0):"Jogada possível apenas se houverem 5 faces iguais";
}
private void verifiqueQuadra() {
int[] facesDoDadoSorteadas = new int[5];
facesDoDadoSorteadas[0]=2;
facesDoDadoSorteadas[1]=2;
facesDoDadoSorteadas[2]=2;
facesDoDadoSorteadas[3]=2;
facesDoDadoSorteadas[4]=3;
jogada = new Jogada(facesDoDadoSorteadas);
assert jogada.jogadaEscolhida(Tipo.QUADRA,0):"Jogada possível apenas se houverem 4 faces iguais ou mais";
}
private void verifiqueFula() {
int[] facesDoDadoSorteadas = new int[5];
facesDoDadoSorteadas[0]=2;
facesDoDadoSorteadas[1]=2;
facesDoDadoSorteadas[2]=3;
facesDoDadoSorteadas[3]=2;
facesDoDadoSorteadas[4]=3;
jogada = new Jogada(facesDoDadoSorteadas);
assert jogada.jogadaEscolhida(Tipo.FULA,0):"Jogada possível apenas se houver uma dupla e uma tripla";
}
}
public class Triangulo {
private int a;
private int b;
private int c;
int get_a() {
return this.a;
}
int get_b() {
return this.b;
}
int get_c() {
return this.c;
}
public Triangulo (int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
public boolean ehEquilatero() {
return (a == b) && (b == c);
}
public boolean ehEscaleno() {
return (a != b) && (b != c) && (c != a);
}
public boolean ehIsoceles() {
return ((a == b) && (b != c)) ||
((b == c) && (a != c)) ||
((a == c) && (b != c));
}
}
-- LeonardoGarcia - 05 Apr 2005
/*
* Main.java
*
* Created on 29 de Março de 2005, 18:02
*/
package xp;
/**
*
* @author grad
*/
public class Main {
/** Creates a new instance of Main */
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Triangulo tri;
if(args.length>0){
tri = new Triangulo(Integer.parseInt(args[0]), Integer.parseInt(args[1]), Integer.parseInt(args[2]));
}else{
tri = new Triangulo(0,3,-3);
}
System.out.println("é isosceles = " + tri.isIsosceles());
System.out.println("é equilatero = " + tri.isEquilatero());
System.out.println("é escaleno = " + tri.isEscaleno());
}
}
/*
* Triangulo.java
*
* Created on 29 de Março de 2005, 18:03
*/
package xp;
/**
*
* @author grad
*/
public class Triangulo {
public int lado1, lado2, lado3;
/** Creates a new instance of Triangulo */
public Triangulo(int lado1, int lado2, int lado3) {
if(lado1==0)
lado1=1;
if(lado2==0)
lado2=1;
if(lado3==0)
lado3=1;
this.lado1 = Math.abs(lado1);
this.lado2 = Math.abs(lado2);
this.lado3 = Math.abs(lado3);
}
public boolean isIsosceles(){
return (lado1==lado2 || lado2==lado3 || lado1==lado3 )&& !isEquilatero();
}
public boolean isEscaleno(){
return lado1!=lado2 && lado2!=lado3 && lado1!=lado3;
}
public boolean isEquilatero(){
return lado1==lado2 && lado2==lado3;
}
}
-- LeonardoGarcia - 22 Jun 2005
package niquel;
import java.util.HashSet;
import java.util.Set;
import src.Jogo;
import src.Jogador;
public class JogoCacaNiquel extends Jogo{
private int aposta;
public JogoCacaNiquel(Set<String> p, int i, int j) {
super(p, i, j);
boolean existeBanca = false;
for (String jog: p){
if (jog.toUpperCase().equals("BANCA"))
existeBanca = true;
}
assert existeBanca: "O jogo iniciou sem a banca como jogador";
aposta = -1;
}
public void jogue(){
assert aposta >= 0: "O jogo Caça-Niquel precisa de uma aposta para ser iniciado";
int[] simbolos = new int[3];
String nomeJogador = "";
for (Jogador jog: _jogadores){
if (!jog.getNome().toUpperCase().equals("BANCA"))
nomeJogador = jog.getNome();
}
Set<String> descricao = new HashSet<String>();
simbolos[0] = ((int)(Math.random() * 15) + 1);
simbolos[1] = ((int)(Math.random() * 15) + 1);
simbolos[2] = ((int)(Math.random() * 15) + 1);
descricao.add("Símbolo 1 = 0" + simbolos[0]);
descricao.add("Símbolo 2 = 0" + simbolos[1]);
descricao.add("Símbolo 3 = 0" + simbolos[2]);
Set<String> vencedores = new HashSet<String>();
if ((simbolos[0] == simbolos[1]) && (simbolos[1] == simbolos[2])){
vencedores.add(nomeJogador);
descricao.add("Ganho = 000" + (2 * simbolos[0] * aposta));
}
else{
vencedores.add("Banca");
descricao.add("Ganho = 0000");
}
this.crieResultado(vencedores, descricao);
}
public void adicioneAposta(int i) {
assert ((i % 25) == 0): "A aposta precisa ser multiplos de R$0,25";
assert i <= 200 : "O jogo Caça-Niquel nao pode conter apostas superiores a R$2,00";
aposta = i;
}
}
-- MarliaSodre - 07 Jul 2005
public class Carta {
public static final int PAUS = 1;
public static final int OUROS = 2;
public static final int ESPADAS = 3;
public static final int COPAS = 4;
private int naipe;
private int valor;
public Carta(int n, int v) {
assert(n >= PAUS && n <= COPAS) : "O naipe deve ser válido";
assert(v >= 1 && v <= 13) : "O valor da carta deve estar entre 1 e 13";
naipe = n;
valor = v;
}
public int getNaipe() {
return naipe;
}
public int getValor() {
return valor;
}
public String toString() {
String tmp = new String("");
switch(valor) {
case 1: tmp = "as"; break;
case 2: tmp = "dois"; break;
case 3: tmp = "tres"; break;
case 4: tmp = "quatro"; break;
case 5: tmp = "cinco"; break;
case 6: tmp = "seis"; break;
case 7: tmp = "sete"; break;
case 8: tmp = "oito"; break;
case 9: tmp = "nove"; break;
case 10: tmp = "dez"; break;
case 11: tmp = "valete"; break;
case 12: tmp = "dama"; break;
case 13: tmp = "rei"; break;
}
switch(naipe) {
case PAUS: tmp = tmp + " de paus"; break;
case OUROS: tmp = tmp + " de ouros"; break;
case ESPADAS: tmp = tmp + " de espadas"; break;
case COPAS: tmp = tmp + " de copas"; break;
}
return tmp;
}
}
-- MarliaSodre - 07 Jul 2005
import java.util.*;
public class Jogo{
private List<String> nomeDosJogadores = new ArrayList<String>();
public boolean jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
return true;
}
private int númeroDeJogadores() {
return nomeDosJogadores.size();
}
public boolean incluirJogador(String nomeDoJogador) {
assert this.númeroDeJogadores() <= 3 : "Jogo tem no máximo três jogadores";
if (nomeDosJogadores.contains(nomeDoJogador))
return false;
nomeDosJogadores.add(nomeDoJogador);
return true;
}
}
package jogo;
import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;
public class Baralho {
private Stack<Carta> monte;
public Baralho() {
monte = new Stack<Carta>();
insiraCartas(Carta.ESPADAS);
insiraCartas(Carta.OUROS);
insiraCartas(Carta.PAUS);
insiraCartas(Carta.COPAS);
embaralhar();
}
private void embaralhar() {
ArrayList<Carta> lista = new ArrayList<Carta>(52);
Carta nula = new Carta();
for(int i = 0; i < 52; i++)
lista.add(nula);
Random random = new Random();
while(monte.size() > 0) {
int pos = random.nextInt(52);
if(lista.get(pos).equals(nula)) {
lista.set(pos,monte.pop());
}
}
monte.addAll(lista);
}
private void insiraCartas(String naipe) {
for(int i = 1; i <= Carta.NUMERO_DE_VALORES; i++) {
monte.add(new Carta(i,naipe));
}
}
public int numeroDeCartas() {
return monte.size();
}
public Carta retirarCarta() {
return monte.pop();
}
}
package jogo;
public class Carta {
public static final String OUROS = "Ouros";
public static final String PAUS = "Paus";
public static final String COPAS = "Copas";
public static final String ESPADAS = "Espadas";
public static final int AS = 1;
public static final int DOIS = 2;
public static final int TRES = 3;
public static final int QUATRO = 4;
public static final int CINCO = 5;
public static final int SEIS = 6;
public static final int SETE = 7;
public static final int OITO = 8;
public static final int NOVE = 9;
public static final int DEZ = 10;
public static final int VALETE = 11;
public static final int DAMA = 12;
public static final int REI = 13;
public static final int NUMERO_DE_VALORES = 13;
public static final int NUMERO_DE_NAIPES = 4;
private int numero;
private String naipe;
public Carta(int numero,String naipe) {
assert (validaNumero(numero) && validaNaipe(naipe)) : "O valor da carta deve estar entre 1 e 13 e seu naipe deve ser válido";
this.numero = numero;
this.naipe = naipe;
}
public Carta() {
numero = -1;
naipe = "";
}
private boolean validaNaipe(String naipe2) {
return (naipe2.equals(OUROS) || naipe2.equals(PAUS)
|| naipe2.equals(COPAS) || naipe2.equals(ESPADAS));
}
private boolean validaNumero(int numero2) {
return (numero2 >= 1 && numero2 <= 13);
}
public boolean equals(Object obj) {
Carta outra = (Carta)obj;
return (naipe.equals(outra.getNaipe()) && numero == outra.getNumero());
}
public String getNaipe() {
return naipe;
}
public int getNumero() {
return numero;
}
}
package jogo;
import java.util.HashSet;
import java.util.Set;
import framework.Jogador;
public class JogadorDeRoubaMontes extends Jogador {
private Set<Carta> monteDeJogo;
private Set<Carta> monteGanho;
public JogadorDeRoubaMontes(String nome) {
super(nome);
monteDeJogo = new HashSet<Carta>();
monteGanho = new HashSet<Carta>();
}
public int numeroDeCartasDeJogo() {
return monteDeJogo.size();
}
public int numeroDeCartasGanhas() {
// TODO Auto-generated method stub
return 0;
}
public void recebaCarta(Carta carta) {
monteDeJogo.add(carta);
}
}
-- AndreGermanoRegert - 04 Jul 2005
O CodigoDoJogoDoMeio foi derivado a partir dos TestesParaOJogoDoMeio.
Foram desenvolvidas as seguintes classes abaixo.
Primeira Iteracao
Segunda Iteracao
Iteracao Final:
package jogo;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import framework.Jogo;
public class JogoRoubaMontes extends Jogo {
private HashMap<String, JogadorDeRoubaMontes> jogadores;
private Set<Carta> mesa;
private String proximo;
private SortedSet<String> sequencia;
public JogoRoubaMontes(Set<String> p, int i, int j) {
super(p, i, j);
}
public JogoRoubaMontes(SortedSet<String> nomes) {
super(nomes, 2, 15);
sequencia = nomes;
jogadores = new HashMap<String, JogadorDeRoubaMontes>();
mesa = new HashSet<Carta>();
for (String nome : nomes) {
jogadores.put(nome, new JogadorDeRoubaMontes(nome));
}
Baralho b = new Baralho();
for (int i = 0; i < 6; i++)
mesa.add(b.retirarCarta());
while (b.numeroDeCartas() != 0) {
for (String nome : nomes) {
JogadorDeRoubaMontes jogador = jogadores.get(nome);
if (b.numeroDeCartas() != 0)
jogador.recebaCarta(b.retirarCarta());
jogadores.put(nome, jogador);
}
}
}
public void jogue() {
this.crieResultado(new HashSet<String>(), new HashSet<String>());
}
public JogadorDeRoubaMontes getJogador(String nome) {
return jogadores.get(nome);
}
public int numeroDeCartasDaMesa() {
return mesa.size();
}
public void jogarRodada(String jogador) {
JogadorDeRoubaMontes jogadorAtual = jogadores.get(jogador);
assert (jogadorAtual != null) : "Só jogadores do jogo podem jogar.";
assert (proximo == null || proximo.equals(jogador)) : jogador
+ " não pode jogar agora. A vez é do(a) " + proximo;
for (Iterator<String> i = sequencia.iterator(); i.hasNext();) {
String j = i.next();
if (j.equals(jogador)) {
if (i.hasNext())
proximo = i.next();
else
proximo = sequencia.first();
break;
}
}
Collection<JogadorDeRoubaMontes> todosOsJogadores = jogadores.values();
for (JogadorDeRoubaMontes j : todosOsJogadores) {
if (!j.equals(jogadorAtual)) {
}
}
}
}
-- MarliaSodre - 07 Jul 2005
public class Jogo{
public void jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
}
private int númeroDeJogadores() {
return 0;
}
public void incluirJogador(String nomeDoJogador) {
}
}
package TrianguloTDD;
public class Testar_Triangulo {
public static void main(String argumento[])
{
Triangulo t = new Triangulo(2,3,4);
assert ( t.éEscaleno()) : "O triangulo (2,3,4) é escaleno";
Triangulo t1 = new Triangulo(2,2,2);
assert ( t1.éEquilátero()) : "O triangulo (2,2,2) é equilátero";
assert ( t1.éIsósceles()) : "O triangulo (2,2,2) é isósceles";
assert (false == t.éIsósceles()) :"NÃO é isósceles o triângulo (2,3,4)";
Triangulo t2 = new Triangulo( 4,4,7);
assert (t2.éIsósceles()) :"é isósceles o triângulo (4,4,7)";
assert (false == t2.éEquilátero()) :"NÃO é equilátero o triângulo (4,4,7)";
assert (false == t2.éEscaleno()) :"NÃO é escaleno o triângulo (4,4,7)";
Triangulo t3 = new Triangulo (2,3,-4);
assert (false == t3.éEquilátero()) :"NÃO é equilátero o triângulo (2,3,-4)";
t = new Triangulo(2,3,100);
assert ( t.éEscaleno()) : "O triangulo (2,3,100) é escaleno";
System.out.println("OK");
}
}
// Classe triangulo ---------------------------------------------------------------------------------------------
/**
* @author grad
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class Triangulo {
static int Escaleno = 0;
static int Isoceles = 1;
static int Equilatero = 2;
private int Tipo = 0;
public Triangulo( int a, int b, int c )
{
if( a == b || a == c || b == c )
Tipo++;
if( a == b && a == c )
Tipo++;
}
public int getTipo()
{
return Tipo;
}
}
// Classe main ---------------------------------------------------------------------------------------------
/*
* Created on 29/03/2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
/**
* @author grad
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class TrianguloTest {
public static void main(String[] args) {
Triangulo t = new Triangulo( Integer.parseInt( args[ 0 ]), Integer.parseInt(args[1]), Integer.parseInt(args[2]));
System.out.println( t.getTipo() );
}
}
-- LeonardoGarcia - 17 May 2005
* CodigoJogo
* CodigoJogador
Código fonte produzido pelo teste:
Table.java
/*
* Created on 07/06/2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package DPh;
import java.util.Vector;
/**
* @author vinicius
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class Table
{
private Vector Philosophers = new Vector();
public void Add( Philosopher P )
{
Philosophers.add( P );
}
public void SetForksTo( Philosopher P ) throws WrongTableException
{
if( !BelongsToThisTable( P ) )
throw new WrongTableException( "Philosopher does not belongs to this table" );
if( !RightPhil( P ).HasLeft() )
P.GetLeftFork();
if( !LeftPhil( P ).HasRight() )
P.GetRightFork();
}
protected Philosopher LeftPhil( Philosopher P ) throws WrongTableException
{
if( !BelongsToThisTable( P ) )
throw new WrongTableException( "Philosopher does not belongs to this table" );
int i = Philosophers.indexOf( P );
int l = i + 1 >= Philosophers.size() ? 0 : i + 1;
return ( Philosopher ) Philosophers.get( l );
}
protected Philosopher RightPhil( Philosopher P ) throws WrongTableException
{
if( !BelongsToThisTable( P ) )
throw new WrongTableException( "Philosopher does not belongs to this table" );
int i = Philosophers.indexOf( P );
int r = i - 1 < 0 ? Philosophers.size() - 1 : i - 1;
return ( Philosopher ) Philosophers.get( r );
}
private boolean BelongsToThisTable( Philosopher p )
{
int i = Philosophers.indexOf( p );
return i >= 0;
}
public void GetForksBack( Philosopher P ) throws WrongTableException
{
if( !BelongsToThisTable( P ) )
throw new WrongTableException( "Philosopher does not belongs to this table" );
P.LeaveLeftFork();
P.LeaveRightFork();
}
}
Philosopher.java
/*
* Created on 07/06/2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package DPh;
/**
* @author vinicius
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class Philosopher
{
private boolean LeftFork = false, RightFork = false;
public Philosopher( Table t )
{
t.Add( this );
}
public void Think()
{
}
public void Eat() throws NoForksException
{
if( !LeftFork || !RightFork )
throw new NoForksException( "Philosopher needs two forks to eat" );
}
public void GetLeftFork()
{
RightFork = true;
}
public void GetRightFork()
{
LeftFork = true;
}
public void LeaveLeftFork()
{
LeftFork = false;
}
public void LeaveRightFork()
{
RightFork = false;
}
public boolean HasLeft()
{
return LeftFork;
}
public boolean HasRight()
{
return RightFork;
}
}
NoForksException?.java
/*
* Created on 07/06/2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package DPh;
/**
* @author vinicius
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class NoForksException extends Exception
{
/**
* @param string
*/
public NoForksException(String string)
{
super( string );
}
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 3257285846578050608L;
}
WrongTableException?.java
/*
* Created on 07/06/2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package DPh;
/**
* @author vinicius
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class WrongTableException extends Exception
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 3256443624949297719L;
/**
*
*/
public WrongTableException()
{
super();
// TODO Auto-generated constructor stub
}
/**
* @param arg0
*/
public WrongTableException(String arg0)
{
super( arg0 );
// TODO Auto-generated constructor stub
}
/**
* @param arg0
* @param arg1
*/
public WrongTableException(String arg0, Throwable arg1)
{
super( arg0, arg1 );
// TODO Auto-generated constructor stub
}
/**
* @param arg0
*/
public WrongTableException(Throwable arg0)
{
super( arg0 );
// TODO Auto-generated constructor stub
}
}
-- LeonardoGarcia - 21 Jun 2005
package src;
import java.util.HashSet;
import java.util.Set;
public abstract class Jogo {
private Resultado resultado;
protected final Set<Jogador> _jogadores = new HashSet<Jogador>();
private int numeroMinimoDeJogadores, numeroMaximoDeJogadores;
public Jogo(Set<String> p, int i, int j) {
numeroMinimoDeJogadores = i;
numeroMaximoDeJogadores = j;
for (String nome : p) {
_jogadores.add(new Jogador(nome));
}
assert this.númeroDeParticipantes() == p.size() : "Os candidatos são os jogadores";
assert numeroMinimoDeJogadores <= númeroDeParticipantes() : "O jogo não conta com o número minimo de jogadores";
assert numeroMaximoDeJogadores >= númeroDeParticipantes() : "O jogo extrapolou o número máximo de jogadores";
}
public abstract void jogue();
protected final void crieResultado(Set<String> vencedores, Set<String> descricao){
Set<String> jogadoresJogo = new HashSet<String>();
for (Jogador jog : _jogadores){
jogadoresJogo.add(jog.getNome());
}
for (String v : vencedores ){
assert (jogadoresJogo.contains(v)): "Resultado com vencedores invalidos";
}
resultado = new Resultado(vencedores,descricao);
}
public final Resultado getResultado(){
if (resultado == null)
throw new AssertionError("Impossivel obter resultado sem jogar");
return resultado;
}
public int númeroDeParticipantes() {
return _jogadores.size();
}
}
*************************************************************************************************************************
package src;
public class Jogador {
private String nome;
public Jogador(String nome) {
this.nome = nome;
}
public String getNome(){
return nome;
}
public boolean equals(Object o){
return nome.equals(o.toString());
}
public String toString(){
return nome;
}
}
*************************************************************************************************************************
package src;
import java.util.Set;
public class Resultado {
private Set<String> vencedores;
private Set<String> descricao;
public Resultado(Set<String> vencedores, Set<String> descricao){
this.vencedores = vencedores;
this.descricao = descricao;
}
public Set<String> getVencedores() {
return vencedores;
}
public Set<String> getDescricao(){
return descricao;
}
}
-- NeyZunino - 08 Jul 2005
package fwjogos;
public class Jogador {
private String nome;
public Jogador(String nome) {
this.nome = nome;
}
public String getNome(){
return nome;
}
public boolean equals(Object o){
return nome.equals(o.toString());
}
public String toString(){
return nome;
}
}
-- NeyZunino - 08 Jul 2005
package fwjogos;
import java.util.HashSet;
import java.util.Set;
public abstract class Jogo {
private Resultado resultado;
protected final Set<Jogador> jogadores = new HashSet<Jogador>();
private int numeroMinimoDeJogadores, numeroMaximoDeJogadores;
public Jogo(Set<String> p, int i, int j) {
numeroMinimoDeJogadores = i;
numeroMaximoDeJogadores = j;
for (String nome : p) {
jogadores.add(new Jogador(nome));
}
assert this.númeroDeParticipantes() == p.size() : "Os candidatos são os jogadores";
assert numeroMinimoDeJogadores <= númeroDeParticipantes() : "O jogo não conta com o número minimo de jogadores";
assert numeroMaximoDeJogadores >= númeroDeParticipantes() : "O jogo extrapolou o número máximo de jogadores";
}
public abstract void jogue();
protected final void crieResultado(Set<String> vencedores, Set<String> descricao) {
Set<String> jogadoresJogo = new HashSet<String>();
for (Jogador jog : jogadores){
jogadoresJogo.add(jog.getNome());
}
for (String v : vencedores ){
assert (jogadoresJogo.contains(v)): "Resultado com vencedores invalidos";
}
resultado = new Resultado(vencedores, descricao);
}
public final Resultado resultado(){
if (resultado == null)
throw new AssertionError("Impossivel obter resultado sem jogar");
return resultado;
}
public int númeroDeParticipantes() {
return jogadores.size();
}
}
-- NeyZunino - 08 Jul 2005
package fwjogos;
import java.util.Set;
public class Resultado {
private Set<String> vencedores;
private Set<String> descricao;
public Resultado(Set<String> vencedores, Set<String> descricao){
this.vencedores = vencedores;
this.descricao = descricao;
}
public Set<String> vencedores() {
return vencedores;
}
public Set<String> descricao(){
return descricao;
}
}
-- LeonardoGarcia - 17 May 2005
package src;
import java.util.ArrayList;
import java.util.List;
public class Jogador {
private String nome;
List<Integer> cartas = new ArrayList<Integer>();
public Jogador(String nome){
this.nome = nome;
}
public void adicionaCarta(int carta){
cartas.add(carta);
}
public int retornaCarta(){
return cartas.remove(0);
}
public int qtdadeCartas(){
return cartas.size();
}
public String retornaNome(){
return nome;
}
public boolean equals(Object o){
return ((Jogador) o).retornaNome().equals(nome);
}
}
-- LeonardoGarcia - 17 May 2005
package src;
import java.util.ArrayList;
import java.util.List;
public class JogoDeGuerra {
private boolean jogoEmAndamento = false;
private List<Jogador> jogadores = new ArrayList<Jogador>();
//private List<Integer> baralho = new ArrayList<Integer>();
public JogoDeGuerra(){
}
public void adicionaJogador(String string) {
assert (jogoEmAndamento == false):"Não pode incluir jogador depois do jogo preparado";
Jogador j = new Jogador(string);
for (int i=0; i<jogadores.size(); i++){
assert (!jogadores.get(i).retornaNome().equals(string)):
"Nao pode adicionar 2 jogadores com nomes iguais";
}
jogadores.add(j);
}
public void preparar() {
assert numeroDeJogadores() >= 2: "Só pode jogar com mais de 2 jogadores";
int[] cartas = new int[13];
int cartaSorteada;
boolean sorteioCorreto;
for (int i=0; i<jogadores.size(); i++){
for (int j=0; j<52/jogadores.size(); j++){
cartaSorteada = (int) (Math.random()*13 + 1);
sorteioCorreto = false;
do {
if (cartas[cartaSorteada - 1] >= 4)
cartaSorteada = (cartaSorteada % 13 ) + 1;
else{
jogadores.get(i).adicionaCarta(cartaSorteada);
cartas[cartaSorteada - 1]++;
sorteioCorreto = true;
}
} while (!sorteioCorreto);
}
}
for(int k=0; k<52 % jogadores.size(); k++){
cartaSorteada = (int) (Math.random()*13 + 1);
sorteioCorreto = false;
do {
if (cartas[cartaSorteada - 1] >= 4)
cartaSorteada = (cartaSorteada % 13 ) + 1;
else{
jogadores.get(k).adicionaCarta(cartaSorteada);
cartas[cartaSorteada - 1]++;
sorteioCorreto = true;
}
} while (!sorteioCorreto);
}
jogoEmAndamento = true;
}
private int numeroDeJogadores() {
return jogadores.size();
}
public int qtdadeCartas(String nome) {
Jogador j = new Jogador(nome);
return jogadores.get(jogadores.indexOf(j)).qtdadeCartas();
}
public int retornaTopo(String nome) {
return jogadores.get(jogadores.indexOf(new Jogador(nome))).retornaCarta();
}
}
package complementoDeDez;
import java.util.*;
public class JogoComplementoDeDez {
private Participantes nomeDosJogadores = new Participantes();
private String vencedor = null;
public JogoComplementoDeDez(Set<String> quemQuerJogar){
assert quemQuerJogar.size() > 1 : "Mínimo de dois jogadores";
for(String jogador : quemQuerJogar) {
nomeDosJogadores.incluir(jogador);
}
}
public int numeroDeParticipantes(){
return(nomeDosJogadores.quantos());
}
public String nomeDoVencedor() {
assert vencedor != null : "pré: para haver vencedor, é preciso antes jogar";
return(vencedor);
}
public void jogar() {
vencedor = nomeDosJogadores.iterator().next();
}
}
-- MichelZanini - 04 Jul 2005
Primeira etapa
Aqui temos o codigo no estado inicial, onde o que esta implementado é somente o necessário para passar nos testes do Framework (Ou seja, ao jogar gerar um resultado);
( CodigoPrimero, TestesPrimeiro )
Segunda etapa - Os placares totais de todos os jogadores comecam com zero e aumentam ao jogar.
Aqui foi necessário criarmos uma Classe JogagoresDePig porque um jogador de Pig tambem tem um placar associado a ele, alem de seu nome. Entao estendemos a classe Jogador do Framework para ser um Jogador especifico de Pig. Com isso foi necessario atribuir a classe JogoDeDadosPig o atributo _jogadoresDePig da Classe recem criada. A partir do momento que temos um placar associado ao jogador entao asseguramos que ele inicie com zero e que se altere ao jogar, deste modo passamos no primeiro teste.
( CodigoSegundo, TestesSegundo )
Terceira etapa - Testar se depois de jogar existe um único jogador com mais de 100 pontos
Para quebrar o que estava implementado, criamos um teste que depois de jogar, testa se existe um ÚNICO jogador que tenha mais de 100 pontos. O teste não passou como esperado. Então implementamos o código abaixo para passar no teste.
( CodigoTerceiro, TestesTerceiro )
Quarta etapa - Testar se há um vencedor, depois de jogar, e se todos os jogadores podem vencer
Criamos o teste para assegurar que existe um vencedor, porque antes ele ainda não existia. Testamos também se o vencedor não sempre o mesmo, para quebrar a implementação anterior onde sempre o mesmo jogar vencia. Para passar neste teste, apenas fizemos um jogador (único) passar de 100 pontos e depois sortamos ao acaso um jogador como vencedor. Isso passou no teste mesmo sabendo que o vencedor nao tem a pontuação mais alta. Isso da margem para criar o proximo teste que justamtente testa isso.
( CodigoQuarto, TestesQuarto )
Quinta etapa - Testar se o vencedor é um jogador e se ele tem um placar >= 100
Aqui sorteamos uma pontuação de 0 a 5(poderia ser outro numero) para aumentar no placar do jogador de forma que o vencedor aque atija 100 pontos primeiro seja o vencedor e que ele seja aleatorio. É conferido também se este vencedor pertence aos jogadores.
( CodigoQuinto, TesteQuinto )
Decidimos fazer um refactoring neste ponto. Ao inves de aumentarPlacar() receber a quantidade de pontos a serem aumentadas pelo metodo jogarJogadaDesteJogador(), faremos um metodo só na classe jogador que representa a sua jogada. Neste metodo é obtido a sua pontuacao e ela ja é incrementada lá mesmo.
( CodigoRefacatoringQuinto )
Sexta etapa - Testar que o jogador não pode aumentar 1 no seu placar, pois se tirar 1 tera soma zero
É testado se no placar do jogardor é aumentado de uma unidade, se isso acontecer quer dizer que o placar tem que permanecer inalterado. Para passar no teste implementamos um condicional que se o resultado do número aleatório for diferente de 1 ele soma o valor ao placar.
( CodigoSexto, TestesSexto )
Sétima etapa - Testar se o jogar joga mais de uma vez por rodada.
Aqui necessitamos acrecentar um atributo a classe JogadorDePig para podermos determinar o número de jogadas necessarias para o jogador. Para assim fazer o teste rodar. Como o teste não passou, implementamos o fato de atribuirmos um valor aleatório de 1 a 6 ao número de jogados.
( CodigoSetimo, TestesSetimo )
Oitava etapa - Testa o fato de que ao jogar mais de uma vez a soma dos valores pode dar mais de 6.
Aqui fizemos um teste da seguinte forma: Se o número de jogadas for maior que 4 e o placar da jogada se altera, quer dizer que o jogador não tirou 1, portanto o mínimo da soma da jogada é 8. O código não passou nesse teste o que nos levou a fazer o jogador jogar o número de vezes correto.
( CodigoOitavo, TestesOitavo )
Nona etapa - Teste de aceitação
Aqui testamos a probabilidade da ocorrencia dos valores dos placares. Onde, os valores menores tem maior probabilidade de ocorrerem. Sendo assim, apos jogarmos varias vezes, temos que: os valores pequenos ocorreram mais vezes q seus respectivos maiores. Se este teste passar, teremos as probabilidades de acordo com o o jogo real. O teste passou.
( CodigoNono, TestesNono )
-- NeyZunino - 08 Jul 2005
package maumau;
import fwjogos.Jogo;
import fwjogos.Jogador;
import java.util.HashSet;
import java.util.Set;
public class JogoMauMau extends Jogo{
public JogoMauMau(Set<String> p, int i, int j) {
super(p, i, j);
}
public void jogue() {
Set<String> vencedores = new HashSet<String>();
Set<String> descricao = new HashSet<String>();
while (vencedores.isEmpty())
proximaJogada();
this.crieResultado(vencedores, descricao);
}
private void proximaJogada() {
// Jogador proximo = proximoJogador();
// proximo.jogue();
}
}
Small Methods: Nine Benefits of Making Your Methods Shorter
I've espoused, on many occasions, making your methods short. The pattern Composed Method, defined by Kent Beck in Smalltalk Best Practice Patterns, says that methods should do things only at one level of abstraction. Methods should be short; a good size for Smalltalk methods is one to a half-dozen lines. That translates to about one to twelve lines (not counting braces!) for Java methods.
I recently engaged in a discussion at JavaRanch where someone thought "20 to 25 lines" was too short. After being taken aback, my response was that there are many reasons that your average method size should be considerably smaller. Here are nine benefits to short methods:
1. Maintenance costs. The longer a method, the more it will take you to figure out what it does, and where your modifications need to go. With shorter methods, you can quickly pinpoint where a change needs to go (particularly if you are coding using test-driven development).
2. Code readability. After the initial learning curve, smaller methods make it far easier to understand what a class does. They can also make it easier to follow code by eliminating the need for scrolling.
3. Reuse potential. If you break down methods into smaller components, you can start to recognize common abstractions in your code. You can minimize the overall amount of code dramatically by reusing these common methods.
4. Subclassing potential. The longer a method is, the more difficult it will be to create effective subclasses that use the method.
5. Naming. It's easier to come up with appropriate names for smaller methods that do one thing.
6. Performance profiling. If you have performance issues, a system with composed methods makes it easier to spot the performance bottlenecks.
7. Flexibility. Smaller methods make it easier to refactor (and to recognize design flaws, such as feature envy).
8. Coding quality. It's easier to spot dumb mistakes if you break larger methods into smaller ones.
9. Comment minimization. While comments can be valuable, most are unnecessary and can be eliminated by prudent renaming and restructuring. Comments that restate what the code says are unnecessary.
You should get the idea that most of the benefits are about improving the design of your system. Breaking methods up into smaller ones obviously leads to lots of smaller methods. You will find that not all of those methods should remain in the same class in which the original method was coded. The small methods will almost always point out to you that you are violating the basic rule of class design: the Single Responsibility Principle (SRP).
The SRP states that a class should have only one reason to change. Put another way, a class should do one thing and one thing only. A class to present a user interface (UI) should do just that. It shouldn't act as a controller; it shouldn't retrieve data; it shouldn't open files; it shouldn't contain calculations or business logic. A UI class should interact with other small classes that do each of those things separately.
Break a class into small methods, and you will usually find all sorts of violations of the SRP.
Initially, you may find it more difficult to work with code with lots of methods. There is certainly a learning curve associated with doing so. You will find that the smart navigational features of your IDE (for example, Eclipse) can go a long way toward helping you understand how all the little methods fit together. In short time, you will find that well-composed code imparts much greater clarity to your system.
One oft-repeated resistance to short methods is that it can degrade performance in your system. Indeed, method calls are usually fairly expensive operations. However, you rarely create performance problems with more methods. Poor performance can usually be attributed to other factors, such as IO operations, network latency, poor choice of algorithm, and other inefficient uses of resources.
Even if additional method calls do noticeably impact performance (performance is not an issue until someone recognizes it as one), it's very easy to inline methods. The rule of performance is always: make it run, make it right (e.g. small methods), make it fast (optimize).
While it's difficult to do, you can go too far and create too many methods. Make sure each method has a valid reason for existing; otherwise inline it. A method is useless if the name of the method and the body of the method say exactly the same thing.
There are exceptions to every rule. There will always be the need for the rare method larger than 20 lines. One way to look at things, however, is to look at smaller methods as a goal to strive for, not a hard number. Instead of debating whether 25 lines, 12 lines or 200 lines is acceptable, see what you can do to reduce method length in code that you would've otherwise not touched. You'll be surprised at how much code you can eliminate.
Few people promote pushing in the other direction. Increasing the average method size represents sheer carelessness or laziness. Take the time and care to craft your code into a better design. Small methods!
Jeff Langr
-- RodrigoPavezi - 05 Jul 2005
-------------------------
Classe JogoDeDadosPig
-------------------------
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogador;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
private final Set<JogadorDePig> _jogadoresDePig = new HashSet<JogadorDePig>();
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
for (Jogador jog : _jogadores) {
_jogadoresDePig.add( new JogadorDePig(jog.getNome()) );
}
}
public void jogue() {
HashSet<String> vencedor = new HashSet<String>();
boolean temGanhador = false;
while (!temGanhador) {
for (JogadorDePig jog : _jogadoresDePig) {
jog.jogarSuaRodada();
if (jog.getPlacarTotal() >= 100) {
vencedor.add(jog.getNome());
temGanhador = true;
break;
}
}
}
crieResultado(vencedor, new HashSet<String>());
}
public Set<JogadorDePig> getJogadores() {
return _jogadoresDePig;
}
}
------------------------------
Classe JogadorDePig
------------------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
private int numeroDeDadosJogados;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public int getNumeroDeDadosJogados() {
return numeroDeDadosJogados;
}
public void jogarSuaRodada() {
numeroDeDadosJogados = (int) (Math.random() * 6) + 1;
int placarDaRodada = 0;
for (int i = 0; i < numeroDeDadosJogados; i++) {
int quantidade = (int) (Math.random() * 6) + 1;
if ( quantidade == 1 ) {
placarDaRodada = 0;
break;
} else {
placarDaRodada += quantidade;
}
}
placarTotal += placarDaRodada;
}
}
-- RodrigoPavezi - 05 Jul 2005
--------------------
Classe JogadorDePig
--------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
private int numeroDeDadosJogados;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public int getNumeroDeDadosJogados() {
return numeroDeDadosJogados;
}
public void jogarSuaRodada() {
numeroDeDadosJogados = (int) (Math.random() * 6) + 1;
int placarDaRodada = 0;
for (int i = 0; i < numeroDeDadosJogados; i++) {
int quantidade = (int) (Math.random() * 6) + 1;
if ( quantidade == 1 ) {
placarDaRodada = 0;
break;
} else {
placarDaRodada += quantidade;
}
}
placarTotal += placarDaRodada;
}
}
package complementoDeDez;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Participantes implements Iterable<String> {
private List<String> _conjunto = new ArrayList<String>();
public boolean incluir(String nome) {
if (_conjunto.contains(nome))
return false;
_conjunto.add(nome);
return true;
}
public boolean éParticipante(String nome) {
return _conjunto.contains(nome);
}
public int quantos() {
return _conjunto.size();
}
public Iterator<String> iterator() {
return _conjunto.iterator();
}
}
-- MichelZanini - 04 Jul 2005
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
}
public void jogue() {
crieResultado(new HashSet<String>(), new HashSet<String>());
}
}
-- RodrigoPavezi - 05 Jul 2005
---------------------------------
Classe JogoDeDadosPig
---------------------------------
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogador;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
private final Set<JogadorDePig> _jogadoresDePig = new HashSet<JogadorDePig>();
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
for (Jogador jog : _jogadores) {
_jogadoresDePig.add( new JogadorDePig(jog.getNome()) );
}
}
public void jogue() {
HashSet<String> vencedor = new HashSet<String>();
boolean temGanhador = false;
while (!temGanhador) {
for (JogadorDePig jog : _jogadoresDePig) {
jog.aumentePlacar(50);
if (jog.getPlacarTotal() >= 100) {
int aleatorio = (int) (Math.random() * _jogadoresDePig.size());
JogadorDePig j = (JogadorDePig) _jogadoresDePig.toArray()[aleatorio];
vencedor.add(j.getNome());
temGanhador = true;
break;
}
}
}
crieResultado(vencedor, new HashSet<String>());
}
public Set<JogadorDePig> getJogadores() {
return _jogadoresDePig;
}
}
-- MarliaSodre - 07 Jul 2005
import java.util.*;
public class Jogo{
private List<String> nomeDosJogadores = new ArrayList<String>();
public boolean jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
return true;
}
private int númeroDeJogadores() {
return nomeDosJogadores.size();
}
public boolean incluirJogador(String nomeDoJogador) {
if (nomeDosJogadores.contains(nomeDoJogador))
return false;
nomeDosJogadores.add(nomeDoJogador);
return true;
}
}
public class Testa29 {
public static void main(String[] args) {
String[] aStr = { "2", "", "2" };
VinteENoveDeMarco.main(aStr);
}
}
-- RodrigoPavezi - 05 Jul 2005
---------------------------
Classe JogoDeDadosPig
---------------------------
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogador;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
private final Set<JogadorDePig> _jogadoresDePig = new HashSet<JogadorDePig>();
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
for (Jogador jog : _jogadores) {
_jogadoresDePig.add( new JogadorDePig(jog.getNome()) );
}
}
public void jogue() {
HashSet<String> vencedor = new HashSet<String>();
boolean temGanhador = false;
while (!temGanhador) {
for (JogadorDePig jog : _jogadoresDePig) {
jog.aumentePlacar(jogarRodadaDesteJogador());
if (jog.getPlacarTotal() >= 100) {
vencedor.add(jog.getNome());
temGanhador = true;
break;
}
}
}
crieResultado(vencedor, new HashSet<String>());
}
private int jogarRodadaDesteJogador() {
int intervaloMaximoDoAleatorio = 5;
return (int) (Math.random() * intervaloMaximoDoAleatorio);
}
public Set<JogadorDePig> getJogadores() {
return _jogadoresDePig;
}
}
---------------------------------------
Classe JogadorDePig
---------------------------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public void aumentePlacar(int quantidade) {
placarTotal += quantidade;
}
}
-- RodrigoPavezi - 05 Jul 2005
----------------------------------------
Refactoring da Classe JogoDeDadosPig
----------------------------------------
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogador;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
private final Set<JogadorDePig> _jogadoresDePig = new HashSet<JogadorDePig>();
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
for (Jogador jog : _jogadores) {
_jogadoresDePig.add( new JogadorDePig(jog.getNome()) );
}
}
public void jogue() {
HashSet<String> vencedor = new HashSet<String>();
boolean temGanhador = false;
while (!temGanhador) {
for (JogadorDePig jog : _jogadoresDePig) {
jog.jogarSuaRodada();
if (jog.getPlacarTotal() >= 100) {
vencedor.add(jog.getNome());
temGanhador = true;
break;
}
}
}
crieResultado(vencedor, new HashSet<String>());
}
public Set<JogadorDePig> getJogadores() {
return _jogadoresDePig;
}
}
----------------------------------------
Refactoring da Classe JogadorDePig
----------------------------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public void jogarSuaRodada() {
int valorMaximoDoIntervaloDeNumAleatorio = 5;
int quantidade = (int) (Math.random() * valorMaximoDoIntervaloDeNumAleatorio);
placarTotal += quantidade;
}
}
-- MichelZanini - 04 Jul 2005
---------------------------------
Classe JogoDeDadosPig
---------------------------------
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogador;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
private final Set<JogadorDePig> _jogadoresDePig = new HashSet<JogadorDePig>();
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
for (Jogador jog : _jogadores) {
_jogadoresDePig.add( new JogadorDePig(jog.getNome()) );
}
}
public void jogue() {
for (JogadorDePig jog : _jogadoresDePig) {
jog.aumentePlacar(1);
}
crieResultado(new HashSet<String>(), new HashSet<String>());
}
public Set<JogadorDePig> getJogadores() {
return _jogadoresDePig;
}
}
---------------------------------------
Classe JogadorDePig
---------------------------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public void aumentePlacar(int quantidade) {
placarTotal += quantidade;
}
}
-- MarliaSodre - 07 Jul 2005
import java.util.*;
public class Jogo{
private List<String> nomeDosJogadores = new ArrayList<String>();
public boolean jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
return true;
}
private int númeroDeJogadores() {
return nomeDosJogadores.size();
}
public boolean incluirJogador(String nomeDoJogador) {
assert this.númeroDeJogadores() <= 3 : "Jogo tem no máximo três jogadores";
if (nomeDosJogadores.contains(nomeDoJogador))
return false;
nomeDosJogadores.add(nomeDoJogador);
return true;
}
public String vencedor() {
return nomeDosJogadores.get(0);
}
}
-- MarliaSodre - 07 Jul 2005
import java.util.*;
public class Jogo{
private List<String> nomeDosJogadores = new ArrayList<String>();
private String vencedor;
public boolean jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
vencedor = nomeDosJogadores.get(0);
return true;
}
private int númeroDeJogadores() {
return nomeDosJogadores.size();
}
public boolean incluirJogador(String nomeDoJogador) {
assert this.númeroDeJogadores() <= 3 : "Jogo tem no máximo três jogadores";
if (nomeDosJogadores.contains(nomeDoJogador))
return false;
nomeDosJogadores.add(nomeDoJogador);
return true;
}
public String vencedor() {
assert vencedor != null : "não há vencedor sem jogo";
return vencedor;
}
}
-- RodrigoPavezi - 05 Jul 2005
-------------------
Classe JogadorDePig
-------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
private int numeroDeDadosJogados;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public int getNumeroDeDadosJogados() {
return numeroDeDadosJogados;
}
public void jogarSuaRodada() {
numeroDeDadosJogados = (int) (Math.random() * 6) + 1;
int quantidade = (int) (Math.random() * 6) + 1;
if (quantidade != 1) {
placarTotal += quantidade;
}
}
}
-- RodrigoPavezi - 05 Jul 2005
---------------------
Classe JogadorDePig
---------------------
/*
* Criado em 04/07/2005
* JogadorDePig.java
* xp
*/
package jogoDeDados.Pig;
import jogoDeDados.Framework.Jogador;
public class JogadorDePig extends Jogador {
private int placarTotal;
public JogadorDePig(String nome) {
super(nome);
placarTotal = 0;
}
public int getPlacarTotal() {
return placarTotal;
}
public void jogarSuaRodada() {
int quantidade = (int) (Math.random() * 6) + 1;
if (quantidade != 1) {
placarTotal += quantidade;
}
}
}
-- RodrigoPavezi - 05 Jul 2005
---------------------------------------
Classe JogoDeDadosPig
---------------------------------------
/*
* Criado em 04/07/2005
* JogoDeDadosPig.java
* xp
*/
package jogoDeDados.Pig;
import java.util.HashSet;
import java.util.Set;
import jogoDeDados.Framework.Jogador;
import jogoDeDados.Framework.Jogo;
public class JogoDeDadosPig extends Jogo {
private final Set<JogadorDePig> _jogadoresDePig = new HashSet<JogadorDePig>();
public JogoDeDadosPig(Set<String> participantes, int minimo, int maximo) {
super(participantes, minimo, maximo);
for (Jogador jog : _jogadores) {
_jogadoresDePig.add( new JogadorDePig(jog.getNome()) );
}
}
public void jogue() {
boolean temGanhador = false;
while (!temGanhador) {
for (JogadorDePig jog : _jogadoresDePig) {
jog.aumentePlacar(50);
if (jog.getPlacarTotal() >= 100) {
temGanhador = true;
break;
}
}
}
crieResultado(new HashSet<String>(), new HashSet<String>());
}
public Set<JogadorDePig> getJogadores() {
return _jogadoresDePig;
}
}
-- LeonardoGarcia - 17 May 2005
* TesteJogo
* TesteJogador
-- MarcusViniciusXavier - 07 Jun 2005
/*
* Created on 07/06/2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package DPhTest;
import DPh.*;
/**
* @author vinicius
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class PhilosopherTest extends Table
{
public static void main( String[] args )
{
test_CanThink();
test_CannotEatWithoutForks();
test_OnlySetForksToOwnedPhil();
test_AfterSetForksHeCanEat();
test_CannotEatAfterGiveForksBack();
test_CanGetRightAndLeft();
test_2PhilCannotEatAtSameTime();
}
private static void test_CanGetRightAndLeft()
{
Table t = new Table();
Philosopher p1 = new Philosopher( t ), p2 = new Philosopher( t );
try
{
if( t.LeftPhil( p1 ) != p2 || t.RightPhil( p1 ) != p2 ||
t.LeftPhil( p2 ) != p1 || t.RightPhil( p2 ) != p1 )
System.out.println( "Right and Left fails" );
}
catch( Exception E )
{
fails = true;
System.out.println( "OK" );
}
}
private static void test_2PhilCannotEatAtSameTime()
{
Table t = new Table();
Philosopher p1 = new Philosopher( t ), p2 = new Philosopher( t );
boolean fails = false;
try
{
t.SetForksTo( p1 );
p1.Eat();
t.SetForksTo( p2 );
p2.Eat();
}
catch( Exception E )
{
fails = true;
System.out.println( "OK" );
}
if( !fails )
System.out.println( "Two philosophers eating at same time" );
}
private static void test_CannotEatAfterGiveForksBack()
{
Table t = new Table();
Philosopher p1 = new Philosopher( t );
try
{
t.SetForksTo( p1 );
t.GetForksBack( p1 );
}
catch( Exception E )
{
System.out.println( E.getMessage() );
}
boolean fails = false;
try
{
p1.Eat();
}
catch( NoForksException E )
{
fails = true;
System.out.println( "OK" );
}
if( !fails )
System.out.println( "Table.GiveForksBack fails" );
}
private static void test_AfterSetForksHeCanEat()
{
Table t = new Table();
Philosopher p1 = new Philosopher( t );
try
{
t.SetForksTo( p1 );
}
catch( Exception E )
{
System.out.println( "Table.SetForksTo fails " + E.getMessage() );
}
boolean fails = false;
try
{
p1.Eat();
}
catch( NoForksException E )
{
fails = true;
System.out.println( "Philosopher has forks but Eat fails " );
}
if( !fails )
System.out.println( "OK" );
}
private static void test_OnlySetForksToOwnedPhil()
{
Table t = new Table(), t1 = new Table();
Philosopher p1 = new Philosopher( t );
boolean fails = false;
try
{
t1.SetForksTo( p1 );
}
catch( WrongTableException E )
{
fails = true;
System.out.println( "OK" );
}
if( !fails )
System.out.println( "Table could set forks to a philosopher that does not belongs to it" );
}
/**
*
*/
private static void test_CannotEatWithoutForks()
{
Table t = new Table();
Philosopher p1 = new Philosopher( t );
boolean fails = false;
try
{
p1.Eat();
}
catch( NoForksException E )
{
fails = true;
System.out.println( "OK" );
}
if( !fails )
System.out.println( "p1.Eat fails" );
}
private static void test_CanThink()
{
Table t = new Table();
Philosopher p1 = new Philosopher( t );
p1.Think();
System.out.println( "OK" );
}
}
package complementoDeDez;
import java.util.HashSet;
import java.util.Set;
public class TestesComplementoDeDez{
//--------------------------------------------------------
public static void main(String[] arg){
umJogoComplementoDeDezTemPeloMenosDoisJogadores();
semCandidatosNãoTemJogo();
umSóCandidatoNaoPodeJogarSozinho();
umVencedorDeveSerUmParticipanteDoJogo();
praHaverVencedorDeveJogarAntes();
System.out.println("OK (TesteJogoComplementoDeDez)");
}
//--------------------------------------------------------
public static void praHaverVencedorDeveJogarAntes() {
Set<String> quemQuerJogar = new HashSet<String>();
quemQuerJogar.add("pedro");
quemQuerJogar.add("maria");
JogoComplementoDeDez jg = null;
jg = new JogoComplementoDeDez(quemQuerJogar);
try {
jg.nomeDoVencedor();
} catch (AssertionError ae) {
assert(ae.getMessage().
equals("pré: para haver vencedor, é preciso antes jogar"));
}
}
//--------------------------------------------------------
public static void umVencedorDeveSerUmParticipanteDoJogo(){
Set<String> quemQuerJogar = new HashSet<String>();
quemQuerJogar.add("pedro");
quemQuerJogar.add("maria");
JogoComplementoDeDez jg = null;
jg = new JogoComplementoDeDez(quemQuerJogar);
jg.jogar();
assert (jg.nomeDoVencedor() == "pedro" || jg.nomeDoVencedor() == "maria");
}
//--------------------------------------------------------
private static void semCandidatosNãoTemJogo() {
Set<String> quemQuerJogar = new HashSet<String>();
try {
JogoComplementoDeDez jg = null;
jg = new JogoComplementoDeDez(quemQuerJogar);
} catch (AssertionError ae) {
assert (ae.getMessage().equals("Mínimo de dois jogadores"));
}
}
//--------------------------------------------------------
private static void umSóCandidatoNaoPodeJogarSozinho() {
Set<String> quemQuerJogar = new HashSet<String>();
quemQuerJogar.add("pedro");
try {
JogoComplementoDeDez jg = null;
jg = new JogoComplementoDeDez(quemQuerJogar);
} catch (AssertionError ae) {
assert (ae.getMessage().equals("Mínimo de dois jogadores"));
}
}
//--------------------------------------------------------
private static void umJogoComplementoDeDezTemPeloMenosDoisJogadores(){
Set<String> quemQuerJogar = new HashSet<String>();
quemQuerJogar.add("pedro");
quemQuerJogar.add("maria");
JogoComplementoDeDez jg = null;
jg = new JogoComplementoDeDez(quemQuerJogar);
assert jg.numeroDeParticipantes() > 1;
}
}
-- MarliaSodre - 07 Jul 2005
public class Jogo{
private int quantidade = 0;
public boolean jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
return true;
}
private int númeroDeJogadores() {
return quantidade;
}
public void incluirJogador(String nomeDoJogador) {
quantidade++;
}
}
-- DaxBogo - 29 Mar 2005
import javax.swing.JOptionPane;
public class Dax_aula1 {
public void roda(){
Triangulo tri = new Triangulo();
String intA = JOptionPane.showInputDialog("Please input lado A");
String intB = JOptionPane.showInputDialog("Please input Lado B");
String intC = JOptionPane.showInputDialog("Please input Lado C");
int a = Integer.parseInt(intA);
int b = Integer.parseInt(intB);
int c = Integer.parseInt(intC);
JOptionPane.showMessageDialog(null, tri.classifica(a,b,c), "Resultado" ,JOptionPane.INFORMATION_MESSAGE);
}
public static void main(String[] args) {
Dax_aula1 programa = new Dax_aula1();
programa.roda();
}
}
public class Triangulo{
public Triangulo(){
}
public String classifica(int ladoA, int ladoB, int ladoC){
String resposta = "Escaleno";
if (ladoA == ladoB && ladoB == ladoC){
resposta = "Equilatero";
}
else {
if (ladoA == ladoB || ladoB == ladoC || ladoA == ladoB){
resposta = "Isoceles";
}
}
return resposta;
}
}
-- MarliaSodre - 07 Jul 2005
public class Jogo{
public void jogar() {
assert this.númeroDeJogadores() >= 2 : "Jogo deve ter no mínimo 2 jogadores";
assert this.númeroDeJogadores() <= 3 : "Jogo deve ter no máximo 3 jogadores";
}
private int númeroDeJogadores() {
return 0;
}
}
-- LeonardoDemilis - 07 Dec 2004
Collective Code Ownership
Leonardo Pereira Demilis
Introdução
Não existem programadores donos do código. Todos devem saber sobre o código e podem altera-lo a qualquer momento.
Em um projeto XP, qualquer par de programadores pode melhorar qualquer trecho de código a qualquer momento. Ou seja, o código inteiro vai se beneficiar da atenção de várias pessoas, o que obviamente aumenta a qualidade do código e diminui os defeitos.
Funciona?
• Unit Tests
• Moving People Around
• Continuous Integration
• Coding Standards
Unit Tests
Para que isto seja possível é necessário ter Unit Tests bem elaborados, permitindo segurança a desenvolvedores que trabalhem neste código.
Moving People Around
Move People Around significa não deixar os desenvolvedores em pares fixos ou em partes fixas do código. Isso traz algumas vantagens:
• Código não fica dependente de um só desenvolvedor.
• Todos os desenvolvedores tem noção de todo o código e de todas as funcionalidades do projeto.
• Treina desenvolvedores com menor skill em determinadas áreas.
• Melhor aproveitamento da equipe. Uma vez que todos trabalham em todas as partes do sistema não vai existir um programador sobrecarregado enquanto outros estão sem o que fazer.
Continuous Integration
“Os diversos módulos do software são integrados diversas vezes por dia e todos os testes unitários são executados. O código não passa até obter sucesso em 100% dos testes unitários”.
As equipes XP mantêm o sistema totalmente integrado, o tempo todo. Diferente do método tradicional, no qual a integração é feita apenas no final, quando todas as partes estão prontas. Isso é muito vantajoso, pois em muitos projetos tradicionais acontecem problemas na hora de fazer a integração.
Ou seja, a integração só no final leva a sérios problemas. Um dos motivos é que, apesar da integração ser crucial, às vezes essa tarefa é delegada a pessoas não familiarizadas com o sistema por completo. Outro problema é que código sem integração muito provavelmente tem bugs. Pois na hora da integração são detectados muitos problemas que não são identificados por meio de outros tipos de teste.
Desenvolvedores muitas vezes nem percebem que o código que eles trabalharam foi modificado ou estendido.
Coding Standards
Evita a perda de tempo corrigindo layout do código.
Equipes XP seguem o mesmo padrão de codificação, para que o código inteiro aparente ter sido escrito pela mesma pessoa. Os detalhes de padronização não são importantes. O importante é que, ao trabalhar com o código de outra pessoa, ele lhe parece familiar, porque o outro programa usando o mesmo padrão que você. Essa prática também oferece suporte à propriedade coletiva de código
Os projetos Java podem usar o "Java Code Conventions", encontrados em http://java.sun.com/docs/codeconv/
Existem algumas outras definições simples que podem facilitar a padronização de código:
• Linguagem das variáveis e métodos (Inglês ou Português)
• Uso de abreviações (Sem abreviações ou Lista de abreviações conhecidas)
• Uso de Maiúsculas/Minúsculas para anagramas (CPF, Cpf ou cpf)
• Uso de plural para Collections (sim ou não)
A ferramenta Checkstyle, que pode ser encontrada em http://checkstyle.sourceforge.net/,
pode ajudar a manter um padrão escolhido para os programadores em Java.
No Delphi, você poderá padronizar a codificação por meio do padrão convencionado pela Borland. Existem, inclusive, ferramentas que realizam a padronização de forma automática num arquivo fonte (*.pas) ou num projeto inteiro.
Bugs
Quem é responsável?
Código de todos ou de ninguém?
Mesmo que todos possam alterar qualquer código, fica claro que quem introduziu uma determinada feature é a pessoa mais indicada a corrigir bugs naquela parte do código. Ou seja, o fato de todos responderem pelo código não impede que haja uma prioridade na responsabilidade por bugs. Embora todos possam ter acesso a qualquer parte do código, é mais produtivo que a pessoa mais familiarizada com ele fique responsável por aplicar as correções.
Vantagens
• Conhecimento do Código
• Não há a necessidade de esperar que o “proprietário” do código faça alterações para você
continuar trabalhando.
• A mudança de um programador qualificado é mais fácil.
Conclusão
Se bem utilizada, e com cuidados pode ajudar muito o desenvolvimento...
Temas já selecionadas:
- XP com Programação Paralela (Filósofos)
- Como as empresas estão implementando XP
reserve seu tema, enviando mail pra mim
-- DaxBogo - 29 Mar 2005
no método:
public static void main(String[] args)
podemos inserir os valores dos lados do triângulo na linha:
tri = new Triangulo(0,1,2);
nesse caso, a resposta é:
é isosceles = true
é equilatero = false
é escaleno = false
Errado pois não existe triângulo com lado 0 (Zero).
BugTodoTrianguloEquilateroEhIsosceles
IsoscelesOuIsoceles
VariaveisDeInstanciaParaOsLadosEramNecessarias
MetodosDeAcessoAosLadosEramNecessarios
ValidacaoDesnecessariaAoTrocarUmLado
SeriaMaisSimplesUsarAssercoes
Um primeiro resultado foi transformarmos a "lista de presença" dessa Aula Aberta em uma lista eletrônica, de modo a podermos divulgar aos interessados os materiais referentes à palestra.
A lista, denominada Agil, pode se constituir ainda em um ponto de encontro entre a comunidade acadêmica e industrial na área das metodologias ágeis.
Os endereços da lista, em princípio, não são disponíveis.
Novos interessados podem se inscrever, enviando mensagem vazia para: agil-subscribe@edugraf.ufsc.br
Os inscritos, para divulgarem algum evento da área para todos os participantes, devem escrever para: agil@edugraf.ufsc.br
>
>
> Tom De Marco ’s view on XP
>
> “The movement called Extreme Programming is to my mind the most encouraging trend in software development today. It focuses us all on the real essentials: talent, discipline without dogma, teamwork, risk-taking, and light process. It poses a particular challenge to the manager, since it pushes control downward (managing people who are empowered to make decisions and even make their own mistakes is a lot harder than managing people who are obliged to shut up and do what you tell them to). I think XP will be a new generation's answer to the mindless regimentation embodied in the C.M.M. and other fat-book methodologies”
>
>
>
http://listas.hipernet.ufsc.br/pipermail/xp/2005-March/000039.html
Tom DeMarco
-- LeonardoGarcia - 12 Apr 2005
- A função que valida os valores do tamanho dos lados ainda deixa valorar "0" como válido.
- As exceções estão sendo diferenciadas pelo texto da mensagem, dificultando a função CATCH posterior. Caso existam muitos tipos de exceções teríamos que montar alguma do tipo SWITH CASE para a mensagem que foi externada, quando poderíamos apenas trabalhar com exceções diferentes.
-- LeonardoDemilis - 30 Nov 2004
XP - Continuous Integration
Metodologia não XP
As equipes são organizadas de modo que uma parte (módulo) fique sob responsabilidade de um desenvolvedor. Cabe a esta pessoa efetuar testes e codificação que dizem respeito a sua parte.
Esta estratégia reduz a complexidade e as preocupações de um desenvolvedor. O desenvolvedor responde somente pelo seu módulo.
Metodologia XP
“Os diversos módulos do software são integrados diversas vezes por dia e todos os testes unitários são executados. O código não passa até obter sucesso em 100% dos testes unitários”.
Esta constante integração além de impedir que se crie uma bola de neve que será muito difícil de trabalhar (ter que demorar semanas para integrar), permite que os desenvolvedores trabalhem sempre com a última versão, não dupliquem funcionalidades que possam ser reaproveitadas e detectando problemas de integração e dando tempo para sua resolução..
Bugs
Na integração são detectados muitos problemas que não são identificados por meio de outros tipos de teste. O período em que as partes são integradas e testadas são extremamente longos. Quanto mais tempo durarem os bugs de integração, mais difíceis serão de se eliminar.
Ferramentas
É muito útil ter um ambiente suportado por boas ferramentas para conseguir automatizar partes do processo de build e integração da aplicação.
Ferramentas de controle de versão como CVS ou Visual Source Safe, são necessárias, e uma ferramenta de script de compilação também (um exemplo para java é o ANT. Mas o make é também muito utilizado). Um framework para Unit Tests (Unit Test Framework) também é essencial. Agora uma ferramenta que coloque todas as outras num trabalho integrado seria perfeito não?
É exatamente isso que a ferramenta Cruise Control faz. Ela foi criada pela equipe do famoso Martin Fowler.
Cruise Control
Criada pela Thought Works (empresa do Martin Fowler). Automatiza o processo de integração contínua.
Como funciona...
* Desenvolvedor-robô que verifica o repositório de fontes (CVS, ClearCase?, Perforce, StarTeam?, VSS) periodicamente.
* Se houve mudança ele faz um checkout, roda todos os testes e publica os resultados em XML (transformado em uma página Web por um servlet).
* Se o último commit fez algum dos testes falhar
* Manda e-mail ao desenvolvedor que fez o commit
* Guarda a última cópia 100% funcional
* Continua a verificar o repositório e quando houver um commit que rode todos os testes, ele incrementa o tag do repositório, publica um novo relatório e atualiza sua cópia.
Conclusão
Se a integração for continua diminui a dor de cabeça que existe ao se integrar duas ou mais partes de um sistema que foram criadas de forma totalmente separadas sem conhecer algumas características uns dos outros.
E existem ferramentas que podem auxiliar na integração como prega a técnica do XP.
Integração contínua "reduz o tempo passado no inferno da integração" [Martin Fowler]
Referências
base:
http://www.xprogramming.com/ftp/Optional+scope+contracts.pdf
tipo resumo- Optional Scope Contracts
8 críticas a XP, incluindo contratos:
http://www.builderau.com.au/manage/project/0,39024668,20266423,00.htm
Um site da Nova Zelândia:
http://www.xp.co.nz/Contracts.htm
Xp em geral, (apresentação):
http://www.ic.unicamp.br/~921234/inf305/xp.pdf
Programação por contratos com XP:
http://www.agilealliance.org/articles/articles/XPAndContracts.pdf (esse é sobre DbC, não contratos comerciais)
BECK, Kent. Extreme Programming Explained.
Referencias sobre Contratos no Desenvolvimento Ágil:
Fixed Price Contract & Agile Software Development - An Experience Report, by Christine Moore
The Rule of 3rds - An Agile Approach, by Christine Moore
Excerpt on Contracts from Lean Software Development, by Mary Poppendieck and Tom Poppendieck
Sample Contract Wording (specifying a Prototype to provide learning)
Sample Language and Stories - Cem Kaner
Pay Per Use Contracts, by Nora Sleumer, Massimo Arnoldi, Massimo Milan Lifeware SA, Switzerland (Submitted to XP2003 Workshop)
Controle de Manutenção
Tecnologias adotadas
- J2EE (JSP/Tomcat)
- MySQL?
- Utilizar jWebUnit para testar a interface WEB?
- Talvez utilizar o Struts como framework?
- que tal experimentar o DBUnit? Dois artigos recentes:
DeveloperWorks article: Control your test-environement with DbUnit and Anthill.
Effective Unit Testing with DbUnit
Histórias
- Usuário detecta problema em um computador, se não conseguir usar o micro com problemas, utiliza o micro ao lado, abre então o navegador e acessa o endereço do Controle de Manutenção. Informa o laboratório e o computador com problema, a descrição do problema e se quiser informa seu e-mail para receber um retorno sobre a resolução do problema.
- O técnico acessa o Controle de Manutenção e verifica os problemas ainda não resolvidos. Escolhe um problema para resolver e muda seu status para indicar que está sendo resolvido.
- O técnico acabou de resolver um problema existente, acessa o Controle de Manutenção e indica que o problema já foi resolvido.
- Técnico deseja ter um controle dos recursos que disponibiliza. Para tal precisa controlar quantas e quais salas possui e o que está disponível, em termos de máquinas e recursos adicionais (projetor, etc.) em cada sala. Para cada máquina que existe ele gostaria de ter um controle individual, podendo definir características particulares a cada uma.
Entidades
- Salas(identificador, capacidade,{Maquina},{RecursosAdicionais})
- Maquina(Sala, identificador,cpu,memoria,{Programa},identificacaoPatrimonio)
- Programa(nome,versao)
- TiposDeRecurso?(descricao)
- RecursoAdicional?(Sala, tipo, identificacaoPatrimonio)
Equipe
Script de criação do banco de dados
CREATE TABLE TIPOSDERECURSOS(TIPORECURSO VARCHAR(50), PRIMARY KEY(TIPORECURSO)) TYPE = INNODB;
CREATE TABLE PROGRAMAS(NOMEPROGRAMA VARCHAR(100), VERSAOPROGRAMA VARCHAR(20), PRIMARY KEY(NOMEPROGRAMA,VERSAOPROGRAMA)) TYPE = INNODB;
CREATE TABLE SALAS(IDSALA VARCHAR(10), CAPACIDADE INTEGER, PRIMARY KEY(IDSALA)) TYPE = INNODB;
CREATE TABLE MAQUINAS(IDSALA VARCHAR(10), IDMAQUINA VARCHAR(20), IDPATRIMONIO BIGINT UNIQUE, CPU VARCHAR(20), MEMORIA SMALLINT, PRIMARY KEY(IDMAQUINA)) TYPE = INNODB;
CREATE INDEX IDXMAQUINASIDSALA ON MAQUINAS(IDSALA);
ALTER TABLE MAQUINAS ADD FOREIGN KEY(IDSALA) REFERENCES SALAS(IDSALA);
CREATE TABLE RECURSOSADICIONAIS(IDRECURSOADICIONAL VARCHAR(20), IDSALA VARCHAR(10), TIPORECURSO VARCHAR(50), IDPATRIMONIO BIGINT UNIQUE, PRIMARY KEY(IDRECURSOADICIONAL)) TYPE = INNODB;
CREATE INDEX IDXRECURSOSADICIONAISIDSALA ON RECURSOSADICIONAIS (IDSALA);
CREATE INDEX IDXRECURSOSADICIONAISTIPORECURSO ON RECURSOSADICIONAIS (TIPORECURSO);
ALTER TABLE RECURSOSADICIONAIS ADD FOREIGN KEY(IDSALA) REFERENCES SALAS(IDSALA);
ALTER TABLE RECURSOSADICIONAIS ADD FOREIGN KEY(TIPORECURSO) REFERENCES TIPOSDERECURSOS(TIPORECURSO);
CREATE TABLE MAQUINAPROGRAMAS(IDMAQUINA VARCHAR(10), NOMEPROGRAMA VARCHAR(100), VERSAOPROGRAMA VARCHAR(20), PRIMARY KEY(IDMAQUINA, NOMEPROGRAMA, VERSAOPROGRAMA)) TYPE = INNODB;
CREATE INDEX IDXMAQUINAPROGRAMASIDMAQUINA ON MAQUINAPROGRAMAS (IDMAQUINA);
CREATE INDEX IDXMAQUINAPROGRAMASNOMEPROGRAMAVERSAOPROGRAMA ON MAQUINAPROGRAMAS (NOMEPROGRAMA,VERSAOPROGRAMA);
ALTER TABLE MAQUINAPROGRAMAS ADD FOREIGN KEY(NOMEPROGRAMA,VERSAOPROGRAMA) REFERENCES PROGRAMAS(NOMEPROGRAMA,VERSAOPROGRAMA);
ALTER TABLE MAQUINAPROGRAMAS ADD FOREIGN KEY(IDMAQUINA) REFERENCES MAQUINAS(IDMAQUINA);
Atividades realizadas
- 14/09 - Estudo inicial do problema. Escolha das tecnologias adotadas.
- 21/09 - Integração com novos membros da equipe. Novo foco inicial de desenvolvimento (nova história - cadastro de recursos)
- Definição de como será trabalhado com o Tomcat (grupo de usuários será criado no servidor liberando acesso a pasta webapps do Tomcat).
- Discussão sobre o problema e definição inicial da estrutura do sistema
- 24/09 - Servidor preparado para acesso pela equipe (conectar via SSH usando as mesmas contas do CVS)
Local da instalação do Tomcat: /usr/local/jakarta-tomcat-5.5.2/webapps -- DiegoAbadan - 24 Sep 2004
- 28/09 - Criação da versão inicial do banco de dados
Plano de trabalho
- 29/09 - Tomcat e MySQL? instalados e bando de dados criado. Início do desenvolvimento da história de cadastro de recursos (elaboração dos testes e possível início de implementação).
Críticas sobre XP
A seguir serão descritas as principais críticas referentes a metodologia XP, fazendo um paralelo com o que aconteceu/está acontecendo na empresa em que trabalhei.
Extreme Programming
Extreme Programming (XP) é uma metodologia de desenvolvimento de software idealizada por Kent Beck. XP é considerada a mais popular das metodologias ágeis de desenvolvimento de software.
A seguir, as principais características de XP:
- Desenvolvimento incremental (small releases)
- Programação em pares
- Refactoring
- Design simples (o mais simples que possa funcionar)
- Interação com o usuário final (Onsite Consumer)
- Código coletivo
- Escrever testes antes de codificar
Estas características são em decorrência dos seguintes valores:
- Simplicidade
- Comunicação
- Coragem
- Feedback
Principais críticas
Com relação às críticas a XP, grande parte delas estão relacionadas com as seguintes práticas:
- Inexistência de documentação
- Representante do cliente acoplado ao projeto
- Programação em pares
- Desenvolvimento dirigido a testes
Inexistência de documentação
A não documentação é considerado por Gerald Keefer como um impecilho ao uso e a manutenção, sendo que o seu custo vale a pena. Além disso, esta prática vai de encontro ao desenvolvimento de software tradicional que afirma que um software não é feito somente de código.
Alternativa (Sengundo Gerold Keefer)
Procurar automatizar o processo de documentação a fim de evitar as prováveis inconsistências. Utilizar XML na documentação é uma abordagem promissora
Representante do cliente acoplado ao projeto
Matt Stephens indaga se o cliente teria como bancar um de seus integrantes 100% do tempo para um único projeto. Além disso, Stephens fala que esse trabalho seria de certo modo "chato" (ficar exclusivamente respondendo aos programadores) e que um integrande experiente (o mais adequato para o projeto XP) não se sujeitaria a tal tarefa, restando apenas os integrantes menos experientes.
Outra crítica, feita por Gerold Keefer, diz que todo desenvolvimento de software gostaria de ter um representante do cliente ao projeto, porém várias experiências reais retratam a dificuldade de se encontrar um pessoa para este papél. Keefer também comenta sobre a experiência obtida no projeto C3 (Chrysler), onde o cliente abandonou o projeto e não pode ser substituído a altura.
Alternativa (Sengundo Gerold Keefer)
Definir uma especificação de requerimentos concisa (como proposta por Robertson). A especificação não precisa ser completa e também não precisa ser completada até o final do projeto.
Programação em pares
Com relação a programação em pares, Matt Stephens acredita que essa prática não deve deve ser adotada durante o tempo todo (como afirma XP) porque o programador necessita estar isolado para se concentrar (meditar). Ele mostra que em um ambiente isolado e calmo a criatividade flui mais facilmente, ajudando na programação. Portanto, Stephens defende que o trabalho em grupo deve ser feito antes da programação e não durante. Outro ponto levantado é a formação de pares discrepantes (expert : newbie), o que pode gerar aborrecimentos ao expert por ter que servir de mentor ao newbie e por não poder programar de maneira mais avançada; e também ao newbie por ter a falsa impressão de ter feito um trabalho brilhante.
Já Gerold Keefer faz referência aos estudos que comprovam a eficiência da programação em pares utilizados como base em XP. Keefer mostra através de outros estudos que não existem evidências sobre a utilidade da programação em pares em revisões e inspeções.
Porém, os dois autores citados anteriormente concordam que em certos casos (debugging, ensino) a programação em pares é bem-vinda.
Mais informações sobre programação em dupla podem ser encontrados em PairProgramming (feito pelo Victor Hugo).
Alternativa (Sengundo Gerold Keefer)
Ao invés de utilizar programação em pares, utilizar a chamada programação mútua onde enquanto um programador termina a codificação o outro analisa e testa o código e vice-versa. Neste caso, os dois programadores podem codificar ao mesmo tempo e em locais diferentes.
Desenvolvimento dirigido a testes
Sobre a prática de se escrever os testes antes, Matth Stephens aponta que como os testes são codificados, eles podem conter bugs da mesma maneira que o código em geral.
Nos mais, Stephens afirma que os testes de unidade pegam somente os bugs de baixo nível, fazendo com que os testes não sejam suficientes para validar se um determinado design está correto. Por outro lado, os testes de aceitação são de muito alto nível, deixando uma brecha entre eles.
Gerald Keefer, que reconhece a importância de XP para a difusão da automatização de testes, diz que a automatização de 100% dos testes não é praticável e que testes manuais são inevitáveis (o que pode exigir um grande esforço devido ao grande número
de releases).
Alternativa (Segundo Matth Stephens)
Utilizar os testes de unidade de maneira inteligente (somente os casos mais importantes) juntamente com revisões e inspeções de processo para os produtos, a fim de depender menos dos testes.
Estudo de caso: XP na empresa Canadas
Na empresa Canadas, grande parte das práticas XP estão sendo adotadas. A empresa, que possui software para gestão de
municípios, vê através das práticas XP uma alternativa para contornar as mudanças de requisitos.
Com relação aos papéis, a empresa está dividida da seguinte maneira: 1 Manager (escudo da empresa), 6 Programmers, 1 Tracker (responsável pelas métricas), 1 Coach (gerencia os programadores) e 1 GoalDonor? (Figura do cliente).
Sobre as práticas abordadas acima, segue uma descrição de como essas práticas foram aplicadas na empresa:
- Inexistência de documentação: não é seguido à risca, o código é documentado juntamente com alguns requisitos.
- Representante do cliente acoplado ao projeto: um membro da empresa faz o papél de cliente visto que ele possui larga experiência em gestão de municípios e é conhecedor das leis vigentes
- Programação em pares: utilizada na maioria das vezes (principalmente na adição de novas funcionalidades).
- Desenvolvimento dirigido a testes: principal desafio. Não está sendo atualmente utilizado devido a dificuldade de sua implantação. No momento, os testes são feitos via JUnit e também manualmente pela a equipe de suporte.
Conclusão
Como XP é uma metodologia recente e bastante inovadora é natural que várias críticas infundadas ou não sejam disparadas pela comunidade de desenvolvimento de software.
A grande força de XP está na união de todas as suas práticas como um complemento uma das outras. Um fator importante, em decorrência disso, é que a metodologia se torna de alto risco visto que se as práticas não forem bem empregadas, o sucesso do projeto pode estar ameaçado. Baseado em: A Self-Referential Safety Net.
Bibliografia
-- AndreChinvelski - 26 Apr 2005
Custos XP x Custos Tradicionais
O objetivo desse trabalho é analisar os custos de XP em relação a outras metodologias.
Custos estão diretamente relacionados com: tempo, qualidade e recursos utilizados. Demonstrando onde XP é melhor nesses aspectos que esse trabalho foi feito. A idéia inicial era fazer um trabalho baseados em dados concretos sobre as práticas de XP, para demonstrar os custos em relação a outras metodologias. Não foi possível obter os dados desejados, no entanto, com uma ánalise em alguns aspectos de XP é possível ter uma idéia das vantagens de XP.
Tempo
O ganho mais significativo está no fato de XP reduzir o tempo gasto na correção de erros, que frequentemente envolvem um grande número de pessoas e muito tempo para fazer a correção.
Em 1999, na Universidade De Utah, foi feita uma pesquisa com graduandos avançados de engenharia de software para analisar a programação em pares. Para isso, o professor responsável pela pesquisa, deu um trabalho para a turma e uma metade da turma fez o software com programação em par e outra individual. Observou-se que a turma que desenvolveu o programa individualmente terminou-o antes, a turma da programação em par levou em média 15% mais tempo. No entanto, o código de quem desenvolveu individualmente continha 15% mais erros, sendo que, em média, para corrigir cada erro eram necessárias 10 horas. Com isso, a turma dos individuais levou 15 vezes mais para terminar o programa.
Outro grande ganho está na interação com o cliente durante o desenvolvimento do projeto. Primeiramente, por que com isso, não ocorre o problema de fazer um software que não condiza com o que o cliente deseja. Dessa forma já se pode ter um grande ganho, tendo em vista que, se o software não condiz com o que o cliente quer, este tem prejuizos e possivelmente a empresa que desenvolveu o software.
Qualidade
A IBM afirmou estar gastando em torno de 250 milhões reparando e reinstalando 30000 problemas reportados. Cerca de 8 mil por cada defeito.
Um software de qualidade tem poucos erros e é de fácil manutenção, evitando perda de tempo com correções. Qualidade se ganha na programação em par e refatoração
As grandes vantagens de XP são notáveis, tanto que mesmo sendo uma metodologia nova vem influenciando várias empresas a adotá-la, tanto empresas novas quanto grandes e mais antigas. Ainda é difícil achar boas estimativas a respeito dos custos, dados concretos comparando as duas. No entanto a idéia de XP é simples e como vimos visivelmente so tem a trazer beneficios.
A satisfação do cliente depende do ciclo de vida XP. O cliente decide que funções o software precisa ter, os programadores estimam os custos, o cliente então faz uma combinação de escolhas entre o que ele realmente necessita baseado no custo. Programadores constroem então o que foi pedido e aprendem a estimar custos no processo. O cliente aprende a definir valores e fazer escolhas efeitvas.
Recursos
Análise prévia é dificil e apresenta alto custo.
Indivíduos e interações ao invés de processos e ferramentas. Recursos são mínimos, basta disciplina.
Conclusão
As grandes vantagens de XP são notáveis, tanto que mesmo sendo uma metodologia nova vem influenciando várias empresas a adotá-la, tanto empresas novas quanto grandes e mais antigas. Ainda é difícil achar boas estimativas a respeito dos custos, dados concretos comparando as duas. No entanto a idéia de XP é simples e como vimos visivelmente so tem a trazer beneficios.
http://walfredo.dsc.ufcg.edu.br/talks/xp-wti.ppt
http://www.scholar.google.com/url?sa=U&q=http://www.cs.waikato.ac.nz/~marku/130/XPSardinia.pdf
http://www.scholar.google.com/url?sa=U&q=http://www.agilealliance.com/articles/reviews/Rumpe2/articles/QuantitativeSurvey.pdf
http://www.dcc.ufla.br/infocomp/artigos/v3.2/art02.pdf
http://c2.com/cgi/wiki?CostingExtremeProgramming
http://www.xprogramming.com/xpmag/BizAnalysis.htm
Como usar o CVS do xp.edugraf.ufsc.br
Informações Gerais
- Endereço do Servidor: xp.edugraf.ufsc.br
- Caminho do repositório de usuário: /cvs/xp/NomeWikiEmMinusculas
- Caminho do repositório de uso comum: /cvs/xp/projetos
- Usuário para acesso: NomeWikiEmMinusculas
- Senha: Definida no cadastro do Wiki.
- Tipo de acesso: SSH.
Como se conectar ao CVS utilizando o Eclipse? (versão 3.0).
- Abrir a perspectiva CVS
- Utilizando o Menu do Eclipse Workbench, vá em: Window -> Open Perspective -> Other...
- Selecione o item CVS Repository Exploring e clique no botão OK.
- Adicionar um repositório na View CVS Repositories
- Clique no botão Add CVS Repository da View CVS Repositories (botão com um ícone amarelo escrito CVS).
- Preencha o formulário da seguinte forma:
- Host: xp.edugraf.ufsc.br
- Repository Path: /cvs/xp/NomeWikiEmMinusculas
- User: NomeWikiEmMinusculas
- Password: Senha definida no cadastro do Wiki.
- Connection Type: extssh
- Deixe as outras opções na forma padrão.
- Poderá ser marcada a caixa Save Password (não recomendado).
- Será adicionado o repositório CVS no Eclipse?! :)
Design By Contract (termo patenteado pelo Meyer!)
Design by Contract
Design by contract is a technique used to help ensure the correctness of software. A software contract is a specification of the behavior of a class and its associated methods. The contract outlines the responsibilities of both the caller (client) and the method being called. Failure to meet any of the responsibilities stated in the contract results in a breach of contract, and indicates the existence of a bug somewhere in the implementation of the software. Contracts increase the reusability and robustness of software while decreasing its complexity. Correctly implemented software contracts reduce the chance that software bugs could remain unnoticed during the testing of a program.
There are three elements essential to defining a software contract: preconditions, postconditions, and invariants. Preconditions and postconditions define the responsibility of the client and method, respectively. Invariants define rules common to both the client and the methods. Defining responsibilities for classes and methods helps you to avoid writing redundant checks because methods and classes are contractually bound to fulfill their part of the contract.
A method's preconditions represent the responsibilities that a client has when making a call to that method. Preconditions specify what a portion of a program's state must be at the entry of a method. If a method's preconditions are violated, then this is a breach of contract, and the method is freed from the responsibility of meeting its postconditions. It is the responsibility of the client to meet a method's preconditions, not the responsibility of the method to verify that its preconditions have been met.
Postconditions are used to specify a method's responsibilities.
-- MeLga - 14 Sep 2004
Desenvolvimento Dirigido por Testes
A Programação Radical é obcecada com feedback, e no desenvolvimento de software, um bom feedback requer bons testes. Os melhores times XP praticam "desenvolvimento dirigido pelos testes", trabalhando em ciclos muito curtos de adicionar um teste, e depois fazê-lo funcionar.
Quase sem esforço, os times produzem código com aproximadamente 100 porcento de cobertura, o que é um grande passo adiante na maioria das empresas.
Não é suficiente escrever testes, é preciso que eles sejam executados. Aqui, também, a Programação Radical é radical. Esses "testes do programador", ou "testes de unidade" são todos agrupados, e cada vez que qualquer programador liberar qualquer código para o repositório (e os pares liberam código duas ou mais vezes ao dia, tipicamente), cada um dos testes de programador deve rodar corretamente. Cem porcento, todo o tempo! Isso significa que os programadores obtém feedback imediato sobre como estão produzindo. Além disso, esses testes fornecem um tremendo suporte para os melhoramentos no design.
-- RudiBravo - 27 Apr 2005
Desenvolvimento Open Source
1.Resumo
Muitas das práticas XP são comuns e necessárias no Desenvolvimento de Softwares Open Source. Vou tentar expor algumas dessas semelhanças, que nem sempre são exatamente iguais, mas apenas uma interpretação da metodologia XP. Vou explorar os valores e não exatamente as tecnicas. Claro que nem todo conteudo de XP, inclusive alguns principais, são abrangidos no desenvolvimento open source, mas vai ficar evidente que esse desenvolvimento com certeza segue uma linha ágil.
2.O Cliente
Um dos requisitos de XP é ter sempre o cliente disponível, não apenas para ajudar a equipe mas também para ser parte dela. Embora o contato seja preferencialmente cara-a-cara, isso não quer dizer que o desenvolvimento open source não tem o cliente sempre presente. No inicio do desenvolvimento, o desenvolvedor é o próprio cliente, desenvolvendo seu produto para uso pessoal, até quando julga que oque esta sendo desenvolvido possa ser benefico para outras pessoas e publica o código. A partir desse instante várias pessoas estão trabalhando juntas para melhorar, mudar e corrigir o código, todos desenvolvedores/clientes. Quando chega a hora de liberar o código para a comunidade, uma grande resposta em forma de review, bug report, usage experience e comparações aparece para a equipe que desenvolveu, a comunidade agora é cliente, e eles se comunicam com os desenvolvedores, assim como os requisitos de XP pedem.
3.Releases
O Planejamento proposto pela metodologia XP é o de pequenas iterações, com vários lançamentos de versões com pequenas alterações, de acordo com o pedido pelo cliente (User Stories). Essas pequenas iterações são planejadas e estudadas individualmente para que se possa cumprir os prasos desejados. No Desenvolvimento Open Source as pequenas iterações estão sempre presentes, porém fogem completamente da metodologia XP quando essas pequenas iterações resultam em pequenos releases com muitos bugs e código sem testes, esperando pelo feedback e relatos de bugs dos usuários. O Planejamento para os prasos também deixa a desejar, embora o desenvolvimento open source tenha prazos, eles não são atendidos com muita frequencia pelo fato de seus desenvolvedores normalmente trabalharem nesses softwares nas horas vagas.
4.Documentação
O uso de uma documentação muito extensa é totalmente desencorajado no XP. Encoraja-se usar padrões de códigos, que deixa o código mais legível e fácil para qualquer membro da equipe entende-lo e modifica-lo. No desenvolvimento open-source não é muito diferente; a maioria dos desenvolvedores tem pratica em fuçar o código para entender o design e nunca precisaram de muito formalismo descrevendo este. Sem contar a grande influencia das listas de discussão, de onde saem a maioria das ideias, sugestoes e assim futuras implementações.
5.Refactoring
Quando nós removemos redundancia, eliminamos funcionalidades sem uso e rejuvenecemos o código, nós estamos praticando Refactoring. Porque é tão dificil fazer isso? Porque nós precisamos reconhecer que um código que nós mesmo desenvolvemos, pode ter sido um excelente meio de resolver o problema quando foi escrito, mas que agora esta defasado, obsoleto, ou até mesmo mal escrito. Na comunidade open source é tão comum lançarem patches, atualizações, que chega uma hora que até mesmo novas funcionalidades são lançadas como patches. É nesse instante que eles param e reescrevem o código, inserindo essa mudanças diretamente no design do programa.
6.KEEP IT SIMPLE
Escrever o código mais simples que você possa ser capaz de escrever é uma das regras de XP. Manter o sistema sem funcionalidades extras é uma premissa básica, para não perder tempo com coisas que não iremos usar. O desenvolvimento open source acaba extrapolando até nesse item, a maioria dos releases iniciais, não fazem nem metade do que deveriam fazer, gerando releases subsequentes que implementem essas funcionalidades.
7.Oque não é XP
Embora muitos pontos levantados mostrem que o desenvolvimento open source pode ser interpretado como seguindo a metodologia XP, existem alguns pontos principais que não nos permitem admitir que esse tipo de desenvolvimento seja XP. Como a falta do TDD, que é um ponto muito critico em XP e classicamente não é abordado no desenvolvimento open source. Não existem as reuniões chamadas STAND-UP MEETINGS também, nem o planejamento do projeto usando os cartões CRC. Contudo, já são usados meios de comunicação como IRC e VoIP? em alguns projetos para completar essa lacuna, e os resultados mostram que realmente pode ser usado XP.
8.Conclusão
Ficou claro que realmente desenvolver softwares open sources não é praticar XP, mas também ficou evidente que existe muito XP no desenvolvimento Open Source, e isso fica mais claro ainda, quando pensamos no desenvolvimento open source como uma mescla de valores e principios, que se assemelham muito com as propostas pela metodologia XP. Ambos podem aprender muito um com o outro, e realmente há certas influencias.
9.Referências
http://freshmeat.net/articles/view/1173/
http://www.extremeprogramming.org/rules.html
http://greg.abstrakt.ch/docs/wyona_oss_development.pdf
http://www.bsdcan.org/2004/papers/opensourcexp.pdf
Coloca o processo tradicional:
--> Projeto
--> Código
--> Testes
de cabeça pra baixo!
Ou seja, T.D.D faz assim :
--> Testes
--> Código
--> (re) Projeto
isso em doses homeopáticas...
a regra que diz que qualquer lado deve ser superior à soma dos outros dois
ver:
Geometria III - Ângulos e Triângulos
Final do Jogo de Dados via TDD
Foi feita uma re-discussão do exemplo apresentado, com a primeira parte de um jogo de dados.
que ainda gerou muita polêmica :-)
O final do jogo ficou como exercício para a turma.
Foi divulgada a nova estóriaDeCliente:
JogoDeGuerra
- Analise dos problemas de desenvolvimento encontrados
- Concentrar em: dificuldade de uma linguagem comum para que os diversos grupos expressassem suas criticas
- Relembrar: programação por contrato (DbC)
- Uma outra forma de encarar o problema: DesenvolvimentoOrientadoPorTestes (TDD)
PorExemplo... ( Classificação de Triângulos usando T.D.D )
Apresentação
Quem precisa de testes?
Discussão e início dos testes do JogoDeGuerra
EquipeUm
EquipeDois
Diagramas de classes que compõem a máquina telis:
Apos ser digitado uma lista de comandos em telis, o parser faz a analise lexica e sintatica dos tokens, verificando se os caracteres são validos se a sintaxe esta correta. Tendo erros, é gerada uma execao, q no caso da maquina é exibido no console. Caso seja um numero, é posto na pilha. Caso seja um identificador é enviado a classe hellcase q verifica se é possivel executar a operacao, verificando se os elementos necessarios para a operacao estao na pilha. Caso seja possivel
ele retorna ao comando para resolver a operacao ( já levando como parametro os elementos da pilha que o proprio hellcase
retirou ), caso contrario, gera uma excecao.
A classe TelisScript é onde se inicia. É a classe que a applet chama.
No pacote Palavras, há a classe Giria, que seria um grupo de comandos, uma agenda.
No pacote Primitivas estao agrupadas grande parte das primitivas, separadas em classes de acordo com sua função.
A classe Ator, que seria o modelo, possui comandos referentes ao modelo, assim como algumas primitivas.
A classe ContextoDeExecucao define o escopo da apique.
FinalizacaoDoExemploInicial
SolucaoDaTurma
ComentariosSobreASolucao
ComecouAEscolhaDeTemasParaApresentacao
Triangulo t = new Triangulo(2,3,4);
assert ( t.éEscaleno ) : "O triangulo (2,3,4) é escaleno"
> Chapter 32
>
>
> Encapsulating Legacy Systems
>
> /*by Mark Wutka*/
>
> ------------------------------------------------------------------------
>
> CONTENTS
>
> * Focusing on Function, not Form
>
>
> * Providing Access to New Systems
>
>
> * Using CORBA to Open Up a Closed System
>
>
> * Encapsulating a TCP/IP System
>
>
> * Encapsulating with Native Method Calls
>
>
> o Wrapping Java Around a Native Interface
>
>
> o Writing Native Methods in C
>
>
> * Encapsulating by Emulating a User
>
>
> * Getting Assistance from the Legacy System
>
>
> * Presenting a Different Interface
>
>
> * Combining Multiple Systems
>
>
> o Handling Deletions Originating in the Legacy System
>
>
> o Using a Two-Phase Commit Protocol
>
>
> o Implementing a Two-Phase Commit
>
>
> * Some Real-World Examples
>
> o An Example Legacy System
>
>
> o Creating a New Application for the Existing Terminal Base
>
> o Creating a New Interface for an Existing Application
>
>
> o Clearing a Path for Migration off the Legacy System
>
>
>
> ------------------------------------------------------------------------
>
> Keeping up with technology is one of the constant problems that most businesses face. You buy a top-of-the-line database system and a year later, after you've spent considerable time converting your organization over to the new database, the database is obsolete. If you try to keep your systems on the leading edge all the time, you'll probably spend more time and money changing systems than you do using them. More likely, you'll keep the old system for a long, long time. Most of these older systems are referred to as "legacy" systems, and while they may not be on the forefront of technology, they are still the lifeblood of many businesses.
>
> By the time you decide to switch systems, all your applications are so heavily tied to the legacy system that you have to rewrite all your applications, making it even more expensive to switch. You have to factor these costs into your decision to switch. You don't switch just to use new technology. You switch because a new system will save you money. If you are more heavily tied to the legacy system, you are more willing to keep using it, because the cost of switching is more than the cost of maintaining the existing system. It is obvious that you could reduce the cost of upgrading and changing systems if you could design your applications so they weren't as dependent on specific products.
>
> As you design new applications, you don't want your design to be constrained by the limits of the current system. Obviously, the implementation will have these constraints, but you want to leave room to grow. Rather than attacking this problem on a per-application basis, take a step back and look at the systems you have today, and try to put a prettier face on them.
>
> You can use a technique called encapsulation to make a legacy system look like a newer system. There is no magic here, since you can't really make the old system work just like a newer one. It won't run any faster, or magically perform some new functions. What encapsulation does is break your dependence on the exact interfaces of the legacy system. For example, suppose you have an MVS system from IBM, and if you are at a large corporation, you probably do. While MVS is expanding its accessibility, you still have some limitations. Suppose, for instance, that you don't have an MVS TCP/IP gateway available and you must use IBM's proprietary SNA protocol to access MVS. How are you going to write an applet to access MVS data? You aren't going to find a copy of the Netscape Navigator that comes with SNA built in. What you can do, however, is write a program that sits in between MVS and the applet and does the necessary translation. Figure 32.1 illustrates an example configuration.
>
> *Figure 32.1 : */An encapsulation program puts a more friendly face on a legacy system/.
>
>
> Focusing on Function, not Form
>
> One of the biggest traps you run into when writing an application is focusing only on the exact form of the data you can get or the exact commands that you can give to the legacy system. What you want to do instead is concentrate on what the legacy system actually does.
>
> For example, suppose you have an ordering system and you want to create a Java applet that can place orders. Assume that you have the following commands on your ordering system:
>
> * START TRANSACTION Begins the ordering process for
> a particular customer.
> * LIST PARTS Gets a list of available parts.
> * ORDER Adds a part to the list of parts
> being ordered.
> * REMOVE Removes a part number from the current list.
> * END TRANSACTION Completes the order.
> * ABORT TRANSACTION Cancels the order.
>
> As you can see by this set of commands, the ordering system requires a high degree of interaction. This set of commands is the "form" of the legacy system. Its function is that it creates orders of parts for your customers. That may seem like a subtle point, but it is very important. One of the reasons we spend so much money re-engineering old applications is that they were too heavily tied to the form of the legacy system.
>
> If you got a new ordering system, the likelihood of the commands being different is fairly high. Most systems use their own set of commands. The function should still be the same for a new system, however. You'll still be using a system to create orders. If you focus on the function of the system and don't worry as much about the actual commands, your applications will adapt to new systems more readily.
>
> Of course, there is a trade-off here. You have to do a little extra work to translate from the legacy system to the application. That's where the encapsulation comes in.
>
> You could, for example, create an encapsulation that placed an entire order at once. It would have methods to list the available parts and place an order. The encapsulation program would translate the order placement into the series of commands expected by the legacy system. Figure 32.2 illustrates how this might take place.
>
> *Figure 32.2 : */An encapsulation can present an interface different from the legacy system/.
>
> This form of encapsulation is actually a design pattern known as a "facade."
>
>
> Providing Access to New Systems
>
> One of the reasons you encapsulate legacy systems is that you want to move to a more modern computing platform. Sometimes the move is on the server side, and sometimes the move is on the client side. For instance, you may want to keep your old mainframe, but upgrade some or all of your workstations to inexpensive Web terminals. Sometimes you want to upgrade the central server or mainframe, but you can't afford to upgrade all your terminals out in the field.
>
> You can often use encapsulation to facilitate a system upgrade. For instance, an airline has a large network of very old terminals, the kind you see every day at the airport. These terminals are connected via a network to a group of mainframes. Now, you realize that it is much more cost effective to develop applications on a UNIX or NT system. In fact, many of your users already have workstations that support a nice graphical interface. Unfortunately, you still have to support the users out in the field, with their old-fashioned terminals. Do you develop your new application on the old mainframe, or do you aim for the new technology? Figure 32.3 illustrates this dilemma.
>
> *Figure 32.3 : */It is difficult to decide whether to extend the legacy system, or put an application on a new system/.
>
> Ideally, the answer to this problem is that you aim for the new technology. Wherever you have to use your legacy technology, encapsulate it and put a pretty face on it.
>
> The practice of separating the application from the user interface is really going to shine for you when you have to deal with legacy systems. If you design your application as you would like it to be, rather than constrain it by the way things are, you can make the existing system fit.
>
> Tip
>
> While "vision" is an overused term these days, you need vision
> when you design applications. You need to be able to look beyond
> what you have right now and see where you want to be, then work
> toward that goal. You'll never escape the legacy system if you
> keep designing it into your new applications.
>
> You design your application the way you want, then adapt the legacy systems to fit your application, not vice versa. For example, suppose you design a new e-mail system using Java for both the client and server. Figure 32.4 illustrates a possible configuration.
>
> *Figure 32.4 : */A Java e-mail system/.
>
> Now that you have your application designed, you concentrate on encapsulating the legacy system to fit into the new application structure. In the case of the e-mail system, you may want to allow the old legacy terminals to access the system. You create an object or a server that looks like a legacy host to the terminals, but looks like a client to the e-mail system. This object would translate the new-user interface into something the legacy terminals understand. Figure 32.5 shows an example of this.
>
> *Figure 32.5 : */You can translate a new-user interface into something a legacy terminal understands/.
>
> You could take a different approach with the new application. Suppose you want to use the existing e-mail application on the legacy system. Maybe it is too expensive or difficult to get the legacy terminals to access the new e-mail application. You could create an object that translates the old e-mail interface into something that looks like the new application, as far as the clients are concerned. Figure 32.6 illustrates this configuration.
>
> *Figure 32.6 : */You can translate a legacy interface into something newer clients can deal with/.
>
> Note
>
> In both of the previous examples, the encapsulation was based on
> the clear separation between the application and user interface.
> Once you separate them, you can translate different application
> interfaces and user interfaces into something that fits your design.
>
>
> Using CORBA to Open Up a Closed System
>
> Once you come up with a way to get data out of your legacy system, you should make it available to other applications using a mechanism that is likely to be supported by many systems. CORBA is a reasonable choice for this, since it is a well-known standard that has been growing in popularity for the last few years. Even if Java's popularity suddenly wanes in favor of something else, you still have a CORBA interface that you could access from other languages.
>
> Figure 32.7 shows some of the ways you can access a legacy system if the encapsulation provides a CORBA interface.
>
> *Figure 32.7 : */CORBA expands the accessibility of an encapsulated system/.
>
>
> Encapsulating a TCP/IP System
>
> If your legacy system can be accessed over the network via TCP/IP, it will be easy for you to access the legacy system. This doesn't mean that it will be easy to write the encapsulation. You may wonder why you even need extra code to encapsulate the system when an applet could make a TCP/IP connection straight to the legacy system (assuming the security restrictions didn't get in the way). Remember that you aren't just encapsulating the access to the system, you are encapsulating the functions it provides.
>
> You don't want to tie your applet to the specific interface provided by the legacy system. This way, if you upgrade the legacy system, you change only the encapsulation, but the applets that talk to the encapsulation don't need to change.
>
>
> Encapsulating with Native Method Calls
>
> Even if your legacy system can run Java, you may still need to create an encapsulation layer. Java may not be able to access the applications running on the legacy system. You can create native methods to handle these situations.
>
> You also may need native methods if you have a special interface card or special interface software to access your legacy system. For example, many IBM systems can only be accessed using the SNA networking protocol. You occasionally need a special interface card to talk to these systems, but many times you just need special networking drivers. Either way, you need a native method to access the special card or drivers.
>
> Figure 32.8 illustrates a typical native method encapsulation.
>
> *Figure 32.8 : */You often need native methods to access a legacy system/.
>
>
> Wrapping Java Around a Native Interface
>
> Suppose your ordering system came with a C library that let you perform all the functions you needed. You could start and end transactions, get a parts list, and add and remove parts from an order. You could create a Java class to access the C library via native method calls.
>
> Listing 32.1 shows a Java interface to the ordering system, with native method calls to the C library.
>
> ------------------------------------------------------------------------
>
> *Listing 32.1 Source Code for **Ordering.java
> *
> package ordering;
>
> // this class provides an interface to an ordering system. It makes
> // calls to native C methods which take care of accessing the real
> // system.
>
> public class Ordering extends Object
> {
> // transactionID is the transaction id returned by the C interface
> // to the ordering system. Each call to the ordering system must
> // be accompanied by the transaction ID.
>
> int transactionID;
>
> // Create an instance of an Ordering object, which begins an ordering
> // transaction.
>
> public Ordering(String customerId)
> throws OrderingException?
> {
> transactionID = startTransaction(customerId);
> }
>
> // Add a part to the current order
>
> public void orderPart(String partNumber, int quantity)
> throws OrderingException?
> {
> orderPart(transactionID, partNumber, quantity);
> }
>
> // remove a part from the current order
>
> public void removePart(String partNumber)
> throws OrderingException?
> {
> removePart(transactionID, partNumber);
> }
>
> // finish the order
>
> public void endTransaction()
> throws OrderingException?
> {
> endTransaction(transactionID);
> }
>
> // abort the order
>
> public void abortTransaction()
> throws OrderingException?
> {
> abortTransaction(transactionID);
> }
>
> // These methods are implemented in a local DLL
>
> protected native int startTransaction(String customerId)
> throws OrderingException?;
>
> public native static String[] listParts();
>
> protected native void orderPart(int txnID, String partNumber,
> int quantity) throws OrderingException?;
>
> protected native void removePart(int txnID, String partNumber)
> throws OrderingException?;
>
> protected native void endTransaction(int txnID)
> throws OrderingException?;
>
> protected native void abortTransaction(int txnID)
> throws OrderingException?;
> }
>
> ------------------------------------------------------------------------
>
> Note
>
> The methods in the Ordering class are not quite a straight
> pass-through to the real ordering system. Rather, it provides a
> slightly higher level of abstraction. It considers an Ordering
> object to be a transaction, and hides the transaction ID from the
> users of the Java class. You will find that many C libraries
> return information that you must use for future function calls.
> You don't actually use the information. Instead, since the library
> has no way of grouping method calls and data together, like an
> object does, the library makes you handle the data and forces you
> to pass it to whatever functions need it. When you design a Java
> interface to a native library, keep information like this hidden
> within the Java class. Don't let the public methods pass back
> anything that isn't useful.
>
> Writing Native Methods in C
>
> Once you have defined a Java class with native methods, you must write the native methods yourself. You can't simply call any arbitrary C function from Java, you almost always have to create a C function that calls the real function you want.
>
> The reason you can't call any arbitrary C function is that native Java methods must conform to a strict naming scheme that combines the method name, the Java class name, and the package name. For example, the declaration for the native C endTransaction method would look like this:
>
> void ordering_Ordering_endTransaction(
> struct Hordering_Ordering *thisPtr, long txnID)
>
> Java always passes a "this" pointer to its native methods, which precludes the use of calling any old C function as a native method. Typically, your native methods will turn around and call other C functions, however.
>
> For instance, your ordering_Ordering_endTransaction function would probably call the endTransaction function in the C library that came with your ordering system.
>
> When you create a Java class with native methods, you have to generate a special header file that contains declarations for the C implementation. You create the header using the javah command. Once the Ordering class has been compiled in Java, you issue the following command:
>
> javah ordering.Ordering
>
> This will generate a header file called ordering_Ordering.h. Next, you must generate a set of stubs, which Java uses to invoke your native methods. You also use the javah command for this, but you must include the -stubs option:
>
> javah -stubs ordering.Ordering
>
> This will create a C file called ordering_Ordering.c. You must compile and link this file into a shared library, along with your native methods. Listing 32.2 shows a skeletal implementation of the native methods for the Ordering class.
>
> ------------------------------------------------------------------------
>
> *Listing 32.2 Source Code for **orderingImpl.c
> *
> #include "ordering_Ordering.h"
>
> /* This is an absolutely skeletal implementation of the
> native methods for the Ordering class. The only method
> that does anything is the listParts method, which returns
> an array of strings. The rest of the methods are dummies.
> */
>
> int nextId = 1; /* For returning different transaction ID's */
>
> /* parts is a list of values that will be returned in listParts */
>
> char *parts[] = {
> "12345 Widget",
> "23456 Deluxe Widget",
> "55534 Thing",
> "30038 Zippy"
> };
>
> struct Hjava_lang_String;
> long ordering_Ordering_startTransaction(struct Hordering_Ordering *thisPtr,
> struct Hjava_lang_String *customerId)
> {
> return nextId++;
> }
>
> HArrayOfString? *ordering_Ordering_listParts(struct Hordering_Ordering *thisPtr)
> {
> HArrayOfString? *retval;
> ClassArrayOfString? *strs;
> int i;
>
> /* Create an array of strings that will contain 4 strings */
> retval = (HArrayOfString? *) ArrayAlloc?(T_CLASS, 4);
> /* If we couldn't allocate the memory, throw a Java exception */
> if (retval == NULL) {
> SignalError?(EE(), "java/lang/OutOfMemoryException", NULL);
> return NULL;
> }
> /* ArrayAlloc? allocated an array of objects, this call makes it an
> array of strings */
>
> unhand(retval)->body[4] = (HString *)
> FindClass?(EE(), "java/lang/String", TRUE);
> /* Get a pointer to the array of strings */
> strs = unhand(retval);
>
> /* Fill the array of strings with Java strings */
>
> for (i=0; i < 4; i++) {
> strs->body[i] = makeJavaString(parts[i], strlen(parts[i]));
> }
>
> return retval;
> }
>
> void ordering_Ordering_orderPart(struct Hordering_Ordering *thisPtr,
> long txnID, struct Hjava_lang_String *part, long quantity)
> {
> }
>
> void ordering_Ordering_removePart(struct Hordering_Ordering *thisPtr,
> long txnID, struct Hjava_lang_String *part)
> {
> }
>
> void ordering_Ordering_endTransaction(struct Hordering_Ordering *thisPtr,
> long txnID)
> {
> }
>
> void ordering_Ordering_abortTransaction(struct Hordering_Ordering *thisPtr,
> long txnID)
> {
> }
>
> ------------------------------------------------------------------------
>
> The skeletal implementation in Listing 32.2 doesn't interface with a real ordering system. Chances are, a real system wouldn't have exactly these methods. For one thing, there are too many things left out. However, for the purposes of illustration, assume that there really is a system that uses the above methods. Once you can access a legacy system, you can change the way it is accessed, as you will see later in this chapter in the section titled "Presenting a Different Interface."
>
>
> Encapsulating by Emulating a User
>
> Sometimes, the only way you can access a legacy system is by interacting with it as if you were a user. This method is more commonly known as "screen-scraping." You basically parse the individual output screens of the legacy application, and generate input to it as if you were a user.
>
> This type of encapsulation is often combined with other methods. For instance, your legacy system may support TCP/IP, but you have to do screen-scraping to get the information from the system, as illustrated in Figure 32.9.
>
> *Figure 32.9 : */Even when a legacy system has TCP/IP, you may have to resort to screen-scraping/.
>
> Sometimes, the only access you can get with a native method is as a terminal to the application, and not directly into the application itself.
>
> You may have to sink so low as to connect up via a modem or a serial cable to do asynchronous communications. You would almost certainly need native methods to do this, although under UNIX, you may be able to get away with doing file I/O. Figure 32.10 illustrates this kind of configuration.
>
> *Figure 32.10: */Sometimes, the only way to get data from a legacy system is via a modem or serial connection/.
>
>
> Getting Assistance from the Legacy System
>
> There's no rule that says that the legacy system can't have an active role in the encapsulation. Many times, you can add code to the legacy system in a few strategic places and open up the system to encapsulation. You can often create simple messaging protocols to pass data to and from the legacy system without having to resort to scraping screens.
>
>
> Presenting a Different Interface
>
> The remnants of a legacy system can stay around long after the system itself is gone. Many times, applications that originally interfaced with the legacy system still do things the way the legacy system did, even though there is no reason for it.
>
> Note
>
> This situation occurs outside the computer industry as well. A
> woman was preparing a ham for a family dinner when her daughter
> asked her why she cut the end off the ham. The woman replied that
> her mother always did it. The woman then asked her mother why she
> always cut the end off the ham. Her mother replied, "So it would
> fit in the pan."
> If you are encapsulating a legacy system, you have the ability to change the interface into the system to some degree. If the legacy system does something in a strange way, use the encapsulation to hide it.
>
> Take the ordering system shown previously, for example. When you create an order, you have to begin a transaction, add parts, then either end or abort the transaction. Maybe you don't want to work that way anymore. You might be better off building an order at the client side, then have the client send the entire order, which is then fed into the system.
>
> This would be more in line with the way Web services work. You try to do everything in one message, since there is no concept of a session on a Web server. Of course, designing your system to work /only/ as a session-less system may also be a bad thing. Do what makes sense for your application.
>
> Tip
>
> You can use this technique when writing an application to use an
> interface that has not yet been completely specified or is
> changing. You decide on the interface your application will use,
> and write your application. When the real interface is completed,
> write an object that translates from one interface to the other.
>
> The ordering system is a good candidate for a different interface. You can easily create an object that lets you place orders in a single, session-less method call, rather than the group of calls in the current interface.
>
> Listing 32.3 shows a simple class with a static method that places an order using the Ordering class.
>
> ------------------------------------------------------------------------
>
> *Listing 32.3 Source Code for **Orders.java
> *
> package ordering;
>
> public class Orders extends Object
> {
> public static void placeOrder(String customerID,
> PartOrder?[] parts) throws OrderingException?
> {
> Ordering ordering = new Ordering(customerID);
>
> for (int i=0; i < parts.length; i++) {
> ordering.orderPart(parts[i].part,
> parts[i].quantity);
> }
>
> ordering.endTransaction();
> }
> }
>
> ------------------------------------------------------------------------
>
> Listing 32.4 shows the PartOrder? class, which encapsulates the information for a single entry in the ordering system.
>
> ------------------------------------------------------------------------
>
> *Listing 32.4 Source Code for **PartOrder.java
> *
> package ordering;
>
> public class PartOrder? extends Object
> {
> public String part;
> public int quantity;
>
> public PartOrder?()
> {
> }
>
> public PartOrder?(String part, int quantity)
> {
> this.part = part;
> this.quantity = quantity;
> }
> }
>
> ------------------------------------------------------------------------
>
> As you can see, the placeOrders method is much easier to use than the regular Ordering object. In a typical ordering system, this simplified interface may be a disadvantage. If this were an airline reservations system, you would have to book all your seats at once and hope that no one got a seat you wanted before you did. When you have a session-based system, you reserve the seats (or the parts) as your transaction progresses. If you abort the transaction, the things you have reserved get freed up for someone else. You will have to decide if you are willing to give up this functionality. It may or may not be worth the cost of a simplified interface.
>
>
> Combining Multiple Systems
>
> One of the more interesting aspects of encapsulation is combining various pieces to present a single, uniform system. It is a task that is both interesting and challenging. A simple example of this might be adding additional customer information to a customer database. For example, suppose your customer database stored the customer's account number, name, shipping address, phone number, and fax number. Now, suppose you have created a new shipping system that allowed customers to get software from you via ftp. You want to add information to the customer database to support this.
>
> If would be nice if you could just add all this information to your legacy system, but maybe that wouldn't be the best thing. Maybe it is so difficult to get data out of the legacy system quickly that your ftp server couldn't service all the requests in a reasonable time.
>
> You can create a separate database containing the information for the ftp server. Your encapsulation would then store information in both the ftp database and the legacy database. Whenever you retrieve information, the encapsulation queries both systems for the information you need.
>
> Tip
>
> Some systems have the ability to maintain information across
> multiple databases. You should see if your legacy system supports
> this kind of thing on its own before you attempt to write it
> yourself. That's a good idea in any situation. A good transaction
> processing (TP) monitor will also handle this kind of situation.
>
> Figure 32.11 shows an encapsulation that stores data in two places.
>
> *Figure 32.11: */An encapsulation can make multiple databases look like one/.
>
> There can be some serious drawbacks to this approach, so you need to be very careful if you decide to try it.
>
>
> Handling Deletions Originating in the Legacy System
>
> If the encapsulation provides the only access to the legacy system, you can control things a lot more easily. If the legacy system is still accessed through some other means, like legacy terminals, you can get into some serious synchronization problems. If someone removes a customer from the legacy database, the other databases don't know about it. If you require all the databases to be in absolute synchronization at all times, this can be a major pain.
>
> You can alleviate this problem by always checking with the legacy database to make sure a record exists. For instance, suppose you removed a customer from the legacy database for some reason, and then that customer tried to access the ftp server. Even though all the information necessary for the ftp is stored in the other database, the encapsulation still checks with the legacy system and learns that the customer account is no longer there.
>
> The problem with this kind of approach is that it is slow. The other database may be a lot quicker than the legacy system, but because you must check with the legacy system each time, you don't realize the speed benefit.
>
> If you are willing to accept a small possibility of discrepancies, you can remove the speed blockage caused by the legacy system. You could run a synchronization program that verified that a particular customer was in both databases, and removed any customers from the other database when they disappear from the legacy database. For a large database, this may be unfeasible.
>
> Some legacy systems keep a transaction log, so you could run a synchronization program that looked for deletions in the transaction log and perform the deletion on the other database. This is a very reasonable solution. You don't have to perform a large number of queries to synchronize the database.
>
> If you are only accessing the databases through the encapsulation, this problem doesn't occur, because the encapsulation knows whenever data is deleted. You may still have some problems if one database is down. You may need a two-phase commit protocol.
>
>
> Using a Two-Phase Commit Protocol
>
> A two-phase commit protocol allows you to make sure an operation can be performed, and then perform it. The idea is that when you have an operation that spans multiple databases, you tell each database, "This is what I want to do, are you ready to do it?" Each database gets ready to perform the operation, or replies that it can't. This is the first phase.
>
> The second phase occurs when all of the databases have responded that they can perform the operation (most of them have actually performed the operation, but not committed it as permanent). You now tell the databases to commit the operation. If one of them fails at this point, you assume that it will be taken care of by the database. In other words, it is the database's responsibility to complete the transaction once it has said that it can.
>
> If, during the first phase, any database refuses to perform the operation, you tell all the databases to back out of the operation. Again, it is the responsibility of the databases to undo whatever changes have been made.
>
> If you have a system that supports the two-phase commit protocol, chances are you can also find a good TP monitor that will supervise the two-phase commit, freeing you from having to write it. If you use a TP monitor, you can always use the native method mechanism to create a Java interface to the TP monitor.
>
>
> Implementing a Two-Phase Commit
>
> When your system doesn't support a two-phase commit, you can either perform a single-phase transaction and log any errors that come up, or you can implement your own two-phase commit. Unless you're anticipating a large number of failures, you may be better off just logging any problems.
>
> Caution
>
> Writing your own two-phase commit protocol is decidedly
> non-trivial. You should have a firm grasp of database techniques
> before you attempt this.
>
> When a database system performs a two-phase commit, it writes the transaction to a log, then performs the transaction without committing it. If the transaction is aborted, it undoes the changes. The log is used in case the database fails during the transaction. Once the database has responded in the first phase, it must be able to either commit or abort the transaction.
>
> Generally, you implement a two-phase commit by saving enough information to be able to restore things to the way they were before the transaction, then performing the transaction. If the transaction is aborted, you put things back the way they were.
>
> If you have a locking mechanism on the legacy system, you should use it while waiting for a commit or abort in the second phase. If you have performed a change in the first phase and another transaction is able to come in and use the changed version of the data, you may not be able to back out of the change. If you are able to lock the data against changes, this can't happen.
>
>
> Some Real-World Examples
>
> If you've never been through a legacy system migration before, you are probably overwhelmed by the number of options and the lack of certainty with which they have been presented. Legacy system migration is often a difficult struggle. The best thing you can do is to approach it with a set of strategies and an open mind, and see what comes up.
>
>
> An Example Legacy System
>
> Suppose you are working with an airline, with a cluster of mainframes, a wide-area network, and thousands of old terminals spread all over the world. The terminals are connected to the mainframe via the wide-area network. Figure 32.12 illustrates this configuration.
>
> *Figure 32.12: */Many legacy systems have a network, one or more mainframes, and a group of terminals/.
>
> Note
>
> The following examples are adapted from actual running systems.
> Your systems may be radically different, but the steps you take
> are roughly the same.
>
> Since you are probably not familiar with the kind of system normally found at an airline, here are thumbnail sketches of the mainframe, the WAN, and the terminals.
>
> * The mainframes run an operating system from IBM called
> Transaction Processing Facility (TPF). It is commonly used by
> large airlines and financial institutions. For this particular
> site, the only connectivity to the mainframes is via thick
> cables called "channel cables." The channel is like an overgrown
> two-way parallel port. The applications running on the mainframe
> are very tightly intertwined, and generally difficult to maintain.
> * The terminals are very old, rugged terminals that run a
> proprietary airline data protocol that is completely
> incompatible with modern data terminals. These legacy terminals
> can display only uppercase letters, digits, and a small set of
> other characters. In addition, they operate in block mode, as
> opposed to single-character mode. That is, when someone enters
> data at the terminal, nothing is sent until the person presses
> the "enter" or "send" key. The idea of "press any key to
> continue" is unheard of on these terminals. Some users in the
> corporate offices have modern PCs, using special gateways to
> talk to the legacy mainframe.
> * The wide-area network is a fairly robust packet-switched network
> that speaks the IBM channel protocol and the proprietary
> terminal protocol. In addition, it supports a number of other
> protocols, including the X.25 standard. This network is very
> modular and programmable.
>
>
> Creating a New Application for the Existing Terminal Base
>
> Suppose you want to create a company-wide e-mail system. You are faced with a number of choices:
>
> * You could write the e-mail system on the existing mainframes.
> This would entail great cost and would not provide any neat GUI
> features for the more modern terminals.
> * You could buy an off-the-shelf e-mail system and put PCs out in
> the field to run it. This is probably the first thing many
> people think of. Unfortunately, it may be even more costly than
> implementing the e-mail system in the mainframe. After all, you
> not only have to buy millions of dollars worth of PCs, you also
> have to put in a distributed LAN infrastructure, and possibly a
> new wide-area network to support it.
> * You could write a custom e-mail system on a modern server, UNIX
> or NT, for example, provide full GUI access to the modern
> terminals, and provide an encapsulation for the legacy terminals
> so they can send and receive mail, too.
>
> Assume that you want to save the company millions of dollars and create a modern
> e-mail system while encapsulating the legacy terminals.
>
> In keeping with the philosophy of not letting the legacy system drag down your design, you design an e-mail system that allows you to send full ASCII text messages, as well as attach binary files to the messages.
>
> Note
>
> Hopefully, you considered buying such a product off-the-shelf.
> There is far too much custom software that needs to be written for
> you to spend your time writing things that have already been done
> a million times.
>
> Armed with your new design, you try to determine how to fit the legacy terminals into the plan. Normally, you have only the mainframe and the terminals to deal with. In this case, however, you have a third element-the network. You could place an encapsulation in two different places. Figure 32.13 shows a scheme where you encapsulate the mail system by making it look like the wide-area network to the terminals. The terminals send information to your encapsulation thinking it is the wide-area network.
>
> *Figure 32.13: */You can encapsulate the mail system by emulating the netwrok/.
>
> Your other option is to make your mail application hook into the network and behave like the mainframe. Figure 32.14 illustrates this configuration.
>
> *Figure 32.14: */You can also encapsulate the mail system by emulating a mainframe/.
>
> Note
>
> There is a third option, which is using the mainframe as the
> front-end for the application, and passing data from the mainframe
> to the application. In this particular solution, however, you want
> to avoid writing code on the mainframe.
>
> Each choice brings its own problems. If you try to emulate the wide-area network, you will probably experience some headaches because you'll have to install code wherever the network connects to the terminals. In general, you want to hook in at as few places as possible, preferably one.
>
> If you try to emulate the mainframe, you want to avoid having to set up your own IBM channel and performing the channel protocol. If you get desperate, you can operate that way. In this case, however, there is a better option.
>
> Recall that the network is highly programmable and supports X.25. Also remember that you may often reap huge benefits by adding a little code to the legacy system to open it up to your encapsulation. By adding some code to the network, you can use X.25 to emulate a mainframe rather than using the channel protocol.
>
> Note
>
> The notion of emulating a legacy host is like a reverse
> screen-scraping. Rather than pulling data off screens generated by
> a legacy system, you're generating the screens.
>
> Figure 32.15 illustrates this configuration.
>
> *Figure 32.15: */A little interface code in the network makes for a simple encapsulation/.
>
> Now that you have a way to emulate a host via X.25, you must decide how you will use the X.25 protocol. You will need to use a native method call of some sort, or, as an alternative, you can create a program in C or C++ that accesses the X.25 line and communicates with users of the X.25 line via TCP/IP. In other words, you create an X.25 server.
>
> Figure 32.16 shows how a Java program could access an X.25 network via this X.25 server.
>
> *Figure 32.16: */A Java program uses a TCP/IP server to access the X.25 network/.
>
> Tip
>
> This technique of creating small servers to handle specific
> interfaces or devices is a reasonable choice for data streams.
> This is much more efficient than CORBA, since you are just passing
> large blocks of data without interpreting it. CORBA is much better
> for message-based communications and remote method invocations.
>
> At this point, you have the connectivity problem solved. You can communicate with the network from your Java program, and you will be able to exchange whatever information you need in order to emulate a mainframe.
>
> Now, you actually implement the encapsulation. The job of the encapsulation is to take a command from a legacy terminal and turn it into a method invocation in the e-mail system, then gather the results and display them in a form that the terminal will understand.
>
> The encapsulation acts like a client to the e-mail system and like a server to the legacy terminal population. Figure 32.17 shows the e-mail system with PC-based clients and legacy terminal clients.
>
> *Figure 32.17: */The e-mail system interacts with both legacy terminals and PC-based terminals/.
>
> As you can see, the e-mail system is not limited by the constraints of the legacy terminal population, but it is still able to service those terminals. Your e-mail system is able to work in the world of distributed clients, where its users may be reading their mail from hand-held terminals and other devices.
>
>
> Creating a New Interface for an Existing Application
>
> Suppose you wanted to create a new interface for a legacy application. In this case, assume that you are trying to put a pretty front-end on an airline reservation system. Your first task, before you even think about connectivity, is designing your reservation system.
>
> Remember, your system doesn't have to work exactly the same way that the existing system does. You'll probably want to simplify the interface and require as little typing as possible.
>
> This is especially important if your goal is to allow agents at the airport to walk around with small hand-held terminals and provide assistance to passengers from outside the confines of a desk. This allows for more personalized service, and this is where you are really going to realize the benefits of Java.
>
> Again, for the sake of simplicity, assume that you have come up with a good, user-friendly design. You aren't ready to move the airline's reservation off the mainframe, however. So, if anyone is going to use your new application, you're going to have to encapsulate the existing reservations system and make it look like your new application.
>
> Now it's time to look at connectivity. Again, you have the mainframe, the network, and the legacy terminals. Start with a simple screen-scraping and proceed from there. In other words, the encapsulation is going to emulate a terminal. You again have choices for where you put your encapsulation:
>
> * You can create an encapsulation that looks like the wide-area
> network, making the mainframe think it is talking to the network
> when it is really talking to your encapsulation. This would let
> your encapsulation emulate whole groups of terminals at once.
> * You can hook your encapsulation into the network as a terminal,
> or cluster of terminals, using the network's X.25 interface.
> * You can write software to emulate an actual legacy terminal,
> which would be both a huge hassle and a huge waste of time.
>
> The X.25 interface looks like the best candidate here because it's cheap and non-proprietary. Plus, you could use the same X.25 server from the e-mail system to access X.25 from Java.
>
> Figure 32.18 shows the relationship between the encapsulation, the X.25 server, and the mainframe.
>
> *Figure 32.18: */The network's X.25 interface permits easy emulation of a legacy terminal/.
>
> In a screen-scraping setup, your encapsulation logs on to the host system with the same commands that a user would normally type. If you are screen-scraping an IBM 3270 application, there's good news and bad news. The bad news is that 3270 screens are no fun to emulate. The good news is that there are some libraries to help you. In the airline example, however, there are no libraries to assist you. After all, it's not like there would be a big customer base for such a library.
>
> You must figure out what commands you would have to enter on the legacy system to perform each task that your new application needs to perform. This may involve single commands to the legacy system, or it may involve a whole series of commands.
>
> Tip
>
> If at all possible, try to minimize the number of extra commands
> your library has to perform each time. For instance, you don't
> want it to go through a complete login sequence every time it
> needs to do commands. Do the minimum number of commands that will
> ensure that your terminal is set up the way you expect.
>
> Once you have your screen-scraping code written, the other side of your encapsulation acts like the server for your new application. In other words, to the regular clients, it looks like the new system. To the legacy system, it looks like a terminal or a group of terminals. Figure 32.19 shows this screen-scraping encapsulation.
>
> *Figure 32.19: */A screen-scraping encapsulation is sometimes your only choice/.
>
> The screen-scraping method of encapsulation is often useful when adding new code to the legacy system is impossible, or cost-prohibitive. Screen-scraping is well-suited for rapid prototyping, however. You can throw a functioning model together fairly quickly, without having to add code to the legacy system.
>
> As a mechanism for a production system, however, screen-scraping has some serious drawbacks:
>
> * If the output for a particular command changes, it could throw
> the screen-scraping code off and give you incorrect results.
> * If the screen-scraper gets out of sync with the host, you can
> get very strange results.
> * Screen-scraping can be very slow, and often performs more
> commands than it needs to.
>
> The nice thing here, however, is that once you have a functioning system, you can work on improving it. If you can get raw data out of the legacy system, you will be much happier. The trick with some systems, like the airline reservation system, is that it wasn't built to give out data in a raw form, so you must add custom code.
>
> When you want to receive raw data from the legacy system, you must decide how the legacy system should deliver the data. The channel interface is a very fast interface, but it takes more work. If you are in a hurry, you may be better off finding an easier solution.
>
> Note
>
> This reluctance to directly hook up to an IBM channel is specific
> to the airline reservation system. If you are connecting to a
> regular SNA host, this is a very viable solution, and there are
> many software/hardware packages available that do this.
>
> You also have the option of making some kind of binary data stream to a terminal, which would most likely require a lot of cooperation from both the legacy system and the network.
>
> The network makes a nice option here. With a little code on the reservation system and on the network, you can get data over the X.25 interface. The legacy system passes data to the network over the channel, and the network hands it to you via the X.25 interface.
>
> Yet again, you have the X.25 server program to keep your Java encapsulation from needing any native methods to access X.25. Unlike screen-scraping, you don't have to perform a series of commands. You can work out a set of messages to be passed between the reservation system and your encapsulation. You won't have to go through the pain of extracting information from text output stream. Instead, the information you need will be laid out in specific places in the messages sent from the reservation system.
>
> Figure 32.20 shows how a Java encapsulation program can use X.25 to exchange binary data with the legacy host.
>
> *Figure 32.20: */Your encapsulation can exchange binary data with the legacy system/.
>
> Assuming you have the time and the resources, a direct channel connection to the mainframe is the best option in terms of bandwidth. When you need such an interface, you may be better off finding a firm that specializes in channel communications and getting them to write the channel interface code.
>
> Assuming you have a way to speak your system's channel code, you should create something similar to the X.25 server. It should speak channel protocol on one side and TCP/IP on the other. Again, this means that you can connect a Java application to the channel gateway with a simple socket instead of creating non-portable native methods.
>
> As with the X.25 solution, when passing information over the channel, you need to figure out what data your encapsulation needs to send and receive, and then add code on the legacy system to handle the requests. Figure 32.21 shows a channel-based encapsulation configuration.
>
> *Figure 32.21: */A direct channel connection to a mainframe gives you high-speed access to data/.
>
>
> Clearing a Path for Migration off the Legacy System
>
> When you encapsulate part of a system in order to use newer technology, you gain more than just the use of the newer technology. You gain a path for migrating off the legacy system.
>
> This whole use of encapsulation boils down to one thing-changing a system in pieces rather than tackling the whole thing at once.
>
> Encapsulation helps insulate you from "flash cuts" where everyone suddenly switches over to a new system. While there are cases when these cuts work, many times you end up switching back and forth while all the bugs are worked out. You'll still have these situations where you go back and forth, but you don't have to switch everything at once.
>
> A typical migration path for upgrading both the legacy system and the legacy terminals usually requires at least one encapsulation. The kind of encapsulation you use depends on which part you want to change first.
>
> Tip
>
> No matter which part of your system you want to change first, the
> first step in migrating away from the legacy system is always the
> same. You have to figure out what the new system is going to look
> like. Until you do that, you can't change a thing.
>
> When you decide to migrate your terminal population first, you must create an encapsulation for the legacy system. You encapsulate the part you aren't changing. As shown in Figure 32.22, you first encapsulate the legacy system, creating what looks like a server for your new application design.
>
> *Figure 32.22: */When migrating legacy terminals, you first encapsulate the legacy system/.
>
> Next, you begin to migrate your terminal population over to the new application design. Since the old terminals and the new terminals are still accessing the same legacy system, you don't run into any coordination problems. Figure 32.23 shows how your terminal population might look halfway through the migration.
>
> *Figure 32.23: */New workstations use the encapsulation to access the legacy system/.
>
> Finally, when all the terminals have been migrated over to the new application design, you can create a new server to replace the legacy system, as shown in Figure 32.24.
>
> *Figure 32.24: */Once the legacy terminals are gone, you can replace the legacy system/.
>
> When you migrate the legacy system first, you encapsulate the terminal population first. In other words, you create an encapsulation that translates commands from the legacy terminals into commands understood by the new application design. Figure 32.25 illustrates this encapsulation.
>
> *Figure 32.25: */A terminal encapsulation allows legacy terminals to access the new system/.
>
> Once the new system is in place, you can migrate your terminals over to the newer terminals. Again, since the new terminals access the same system as the old system, you don't have any coordination problems-there is only one system running. Figure 32.26 illustrates this migration in the process of changing the terminals over.
>
> *Figure 32.26: */Legacy terminals and new workstations access the new system/.
>
> Finally, when you have migrated the last terminal over to the new application design, you are done.
>
> Legacy system is a lot harder than it sounds. The techniques presented in this chapter represent your battle strategy. You use them to attack each new legacy system in a different way. Even though you have a good strategy, you still have to fight the battle-or write the code, in this case. That's where the real fun begins. Each system has its own challenges. You may not enjoy it while you're doing it, but sometime down the road, you'll enjoy recounting all the peculiarities of each system you worked with. They all have their own personalities, brought about by years of tweaks and changes.
>
> Legacy system migration is crucial to bringing more companies onto the Internet and really advancing into the information age. Very few companies want to create a new system from scratch just so they can be on the Net.
>
Vinicius, André e Jader
-- DaxBogo - 29 Mar 2005
Dax Barreto Bogo
Rudi de Andrade
Suzana Souza
Marília Sodre
-- MateusLudwich - 17 May 2005
Possíveis testes:
não podem haver mais jogadores do que cartas
um jogador só pode jogar se ele tiver pelo menos uma carta
não pode jogar com jogo sem jogadores
não pode jogar com um jogador
com dois ou mais jogadores é possível jogar o jogo
não podem haver dois jogadores com mesmo nome
um dos jogadores é o vencedor
para haver vencedor, é preciso antes jogar
André Luiz Cardoso
Fernando Luiz C. Cardoso
Thiago Napoleão Gilioli
-- LeonardoGarcia - 17 May 2005
Código desenvolvido por :
Leonardo Garcia
Rudi Bravo
* CodigoTeste
* CodigoFonte
-- LuizSouza - 01 Sep 2004
EQUIPES XP NAS EMPRESAS
I – CARACTERÍSTICAS GERAIS DE UM PROJETO XP
- Grupos de 2 a 10 programadores
- Projetos de 1 a 36 meses (calendário)
- De 1000 a 250 000 linhas de código
- Papéis:
- Programadores
- Testadores (que ajudam o cliente com testes de aceitação)
- Analistas (que ajudam o cliente a definir requerimentos)
- Gerente (garante os recursos necessários)
- Coach (orienta a equipe, controla a aplicação do XP)
- Tracker (coleta métricas)
II - PRÁTICAS DA METODOLOGIA XP
Kent Beck descreve doze práticas que devem ser seguidas na metodologia XP:
- PLANEJAMENTO – O cliente escreve “histórias” sobre as funcionalidades que ele deseja do sistema. Os programadores interagem com o cliente e discutem e experimentam diferentes tecnologias e arquiteturas para o sistema, estabelecendo então as estimativas de prazo e prioridades de cada tarefa
- FASES PEQUENAS – produzir rapidamente um sistema simples e 100% funcional e a seguir libere versões novas em um ciclo muito curto.
- METÁFORA - equipes XP mantém uma visão compartilhada do funcionamento do sistema inteiro.
- DESIGN SIMPLES - o sistema deve ser projetado o mais simples possível em todo o momento. A complexidade extra deve ser removida assim que for descoberta.
- TESTES - os programadores escrevem continuamente os testes de unidade, que devem funcionar como um guia para o desenvolvimento.
- REFATORAMENTO - os programadores reestruturam o sistema sem mudar seu comportamento, para remover a duplicação, melhorar a comunicação, simplificar, ou adicionar a flexibilidade.
- PROGRAMAÇÃO EM PARES - todo o código é escrito com dois programadores em uma máquina.
- PROPRIEDADE COLETIVA - qualquer um pode mudar todo o código em qualquer lugar no sistema em qualquer hora.
- INTEGRAÇÃO CONTÍNUA - manter o sistema integrado continuamente, evitando preocupações futuras.
- SEMANA DE 40 HORAS - trabalhe 40 horas na semana em regra geral. Nunca trabalhe fora do tempo estipulado.
- CLIENTE JUNTO AOS DESENVOLVEDORES - inclua pelo menos um cliente na equipe, disponível o tempo todo para responder a perguntas.
- PADRONIZAÇÃO DO CÓDIGO – os programadores escrevem todo o código de acordo com as regras adotadas pelo grupo inteiro.
III - ESTUDO DE CASO
a) Motivação
Interesse em confrontar estas práticas com o que realmente é adotado nas Empresas.
- Como implantar equipes XP nas empresas ?
- Como fazer a definição de papéis ?
- Como serão avaliados os resultados de produção individual ?
- Estudo de caso ?
b) Como o Trabalho foi feito:
Feito uma busca de artigos na Internet que relatam experiências práticas usando a metodologia XP:
-- AndreChinvelski - 29 Mar 2005
Comentários:
A classe só tem um método, não possui atributos, poderia ter sido feito como um método estático.
public class Main {
public void roda(){
Triangulo tri = new Triangulo();
System.out.println(tri.classifica(0,0,1)+" Não existe triângulo com lados: 0, 0, 1");
System.out.println(tri.classifica(1,-6,1)+" Não existe triângulo com lados: 1,-6 , 1");
System.out.println(tri.classifica(2,1,6)+" triângulo com lados: 2, 1, 6 OK");
System.out.println(tri.classifica(1,1,1)+" triângulo com lados: 1, 1, 1 OK");
System.out.println(tri.classifica(2,1,1)+" triângulo com lados: 2, 1, 1 OK");
}
public static void main(String[] args) {
Main programa = new Main();
programa.roda();
}
}
-- LeonardoGarcia - 21 Jun 2005
Caça-níquel
Este é um dos jogos mais populares em casinos. Foi inventado no século XVII por um cientista francês, Blaise Pascal, que realizava pesquisas sobre movimentos uniformes. Em 1842, Frenchmen François e Louis Blanc aperfeiçoaram a máquina e a levaram para Hamburgo, Alemanha, já que os jogos de azar estavam proibidos na França. Mais tarde, o próprio François e seu filho, Camille, foram os responsáveis por mostrar o caça-níquel a Charles III, Príncipe de Mônaco. O nobre gostou tanto do mecanismo que acabou construindo o famoso resort de Monte Carlo só para poder ir jogá-lo.
Cada rolo tem um número de símbolos,(tipicamente de 10 a 20 – que variam dependendo da máquina), e o puxar da alavanca faz com que os rolos girem rapidamente. Quando eles começam a parar independentemente, cada rolo indicará aleatoriamente um dos símbolos através do visor na máquina. Dependendo da combinação dos símbolos, o jogador ganhará quantias diferentes de pagamento [ ENDASH ] muitas vezes bem mais do que a aposta original.
O jogo criado tem 15 símbolos gerais representados por números de 1 a 15. Cada rodada consta com a aleatoriedade de 3 rolos dos símbolos supracitados. O prêmio só é concedidos quando existirem 3 símbolos sorteados iguais. O prêmio retornado para o usuário é duas vezes o valor do símbolo (quando vitorioso) multiplicado pela aposta.
Ex. O jogador apostou R$0.50 e obteve uma tripla 13. Seu prêmio será 2 x 13 x R$0.50 = R$13,00
As apostas podem variar de R$0,25 a R$2,00 variando em R$0,25.
-- AndreGermanoRegert - 07 Jul 2005
Estórias:
Jogo:
Ao abrir-se o jogo:
- deve-se perguntar quantos jogadores irão jogar, mínimo de 2 e máximo de 5
- recolhe-se o nome de cada jogador
- cada jogador deve iniciar com zero pontos
Ao iniciar o Jogo:
- O baralho deve ser embaralhado.
- Viram-se as duas primeiras cartas do baralho
- Comparam-se as cartas. Se as duas cartas viradas tiverem uma diferença de valor menor do que 3 ou maior do que 10, o baralho deve ser reembaralhado.
Uma jogada consiste de:
- perguntar aos jogadores se a proxima carta esta entre o intervalo ou fora dele.
- Cada jogador responde se sim ou se nao esta.
- Após todos os jogadores responderem, a proxima carta deve ser virada.
- verificar quem acertou e quem errou e dar 100 pontos aos vencedores.
O jogo termina quando:
- o baralho chegar ao fim.
- vence o jogador que tiver mais pontos.
- pergunta se os jogadores desejam jogar novamente.
Baralho:
o baralho :
- deve ter 52 cartas tradicionais, os quatro naipes de Ás a Rei.
- pode ser embaralhado quando estiver completo
- Tem a possibilidade de tirar uma carta de cima de cada vez
- retornar as cartas apos todas serem viradas
Jogador:
o Jogador deve:
- ter um nome
- saber quantos pontos possui
-- AndreGermanoRegert - 04 Jul 2005
Estórias do Usuário:
Jogo:
Ao abrir-se o jogo:
- deve-se perguntar quantos jogadores irão jogar
- recolhe-se o nome de cada jogador
- cada jogador deve iniciar com zero pontos
Para iniciar o Jogo:
- Deve haver pelo menos dois jogadores
- O baralho deve ser embaralhado e as duas primeiras cartas
viradas. Se as duas cartas viradas tiverem uma diferença de
valor menor do que 3 ou maior do que 10, o baralho deve ser reembaralhado.
Uma jogada consiste de:
- Cada jogador fazer dizer se o valor da proxima carta do
baralho estará entre as duas cartas viradas ou não.
- Uma carta ser virada do topo do baralho
- verificar quem acertou e quem errou e distribuir os pontos
- Cada um dos vencedores ganha 100 pontos.
O jogo termina quando:
- o baralho chegar ao fim.
- vence o jogador que tiver mais pontos.
Baralho:
O baralho :
- deve ter 52 cartas tradicionais, os quatro naipes de Ás a Rei.
- pode ser embaralhado quando estiver completo
- Tem a possibilidade de tirar uma carta de cima de cada vez
- retornar as cartas apos todas serem viradas
Jogador:
o Jogador deve:
-- AndreGermanoRegert - 06 Jul 2005
Estórias do Usuário:
Jogo:
Ao abrir-se o jogo:
- deve-se perguntar quantos jogadores irão jogar, num mínimo de 2 e máximo de 5
- recolhe-se o nome de cada jogador
- cada jogador deve iniciar com zero pontos
Para iniciar o Jogo:
- O baralho deve ser embaralhado e as duas primeiras cartas
viradas. Se as duas cartas viradas tiverem uma diferença de
valor menor do que 3 ou maior do que 10, o baralho deve ser reembaralhado.
Uma jogada consiste de:
- Cada jogador fazer dizer se o valor da proxima carta do
baralho estará entre as duas cartas viradas ou não.
- Uma carta ser virada do topo do baralho
- verificar quem acertou e quem errou e distribuir os pontos
- Cada um dos vencedores da rodada ganha 100 pontos.
O jogo termina quando:
- o baralho chegar ao fim.
- vence o jogador que tiver mais pontos.
Baralho:
O baralho :
- deve ter 52 cartas tradicionais, os quatro naipes de Ás a Rei.
- pode ser embaralhado quando estiver completo
- Tem a possibilidade de tirar uma carta de cima de cada vez
- retornar as cartas apos todas serem viradas
Jogador:
o Jogador deve:
- ter um nome
- saber quantos pontos possui
-- AndreGermanoRegert - 06 Jul 2005
Writing User Stories and Planning XP Projects
-- MateusLudwich - 01 May 2005
Dado o seguinte problema / Dada a seguinte especificação:
Elaborar uma aplicação, com interface gráfica, para:
1 - Ler e validar AFD e AFND (pode ser na forma de tabela de transição)
2 - Ler e validar GR
3 - Reconhecer sentenças aceitas por AFD e AFND e geradas por uma GR
4 - Converter GR para AF
5 - Converter AF para GR
6 - Determinizar AFND
7 - Minimizar AFD
Observações:
1 - Pode-se usar apenas letras maiúsculas para representar Não-Terminais e
Estados
2 - Os terminais podem ser quaisquer caracteres especiais, dígitos ou letras
minúsculas
3 - Os nomes de símbolos e estados não devem ser pré-estabelecidos
4 - Além da corretude, serão observados aspectos como usabilidade e robustez da
aplicação.
Será possível usar TDD neste caso?
Tentando usar TDD, precisamos criar a princípio uma Infra-Estrutura de
testes. Infra-Estrutura de testes para testar o que?
Bem, podemos observar claramente dois elementos deste problema: gramáticas e
autômatos, podemos criar uma infra-estrutura de teste para cada um. Há um outro
elemento que pertence à aplicação em si que é a interface gráfica com o
usuário, para a qual também podemos criar uma infra-estrutura de teste.
Pensando assim podemos ter o seguinte teste para gramática:
TesteGR00
Ao criarmos uma Infra-Estrutura para gramática e adicionarmos este teste nela
(fase amarela o teste falha). Assim passamos para a fase vermelha.
Criando a classe GramaticaRegular e escrevendo um método chamado "ehRegular()"
que retorna sempre "true" passamos para a fase verde.
FaseVerde01
Agora precisamos fatorar:
O código feito aparentemente não pode ser simplificado;
O código não parece ter duplicações;
Entretanto passou-se no teste escrito pois o método sempre retorna true.
Devemos fazer um método que retorne true apenas se a gramática for regular.
Para isto precisamos de uma gramática definida. Mas o teste atual não está
definindo nenhuma gramática!
Caímos então na necessidade de fatorar o código de testes:
Como fazer um teste que explicite/defina uma gramática?
Sabemos que uma gramática é definida da seguinte maneira:
G = (Vn,Vt,P,S)
onde,
Vn - conjunto finito de símbolos não-terminais, que no caso deverão ser
representados por letras maiúsculas;
Vt - conjunto finito de símbolos terminais, que no caso podem ser quaisquer
caracteres especiais, dígitos ou letras minúsculas;
P - conjunto finito de pares (a, b) denominados produções (ou regras
gramaticais ou de sintaxe);
S - É o símbolo inicial da gramática.
Para que o teste explicite uma gramática ele deve conter então uma lista de
Vn´s (letras maiúsculas), uma lista de Vt´s (letras minúsculas, caracteres
especiais ou dígitos), uma lista de pares (a, b), e um S (letra maiúscula que
indica o símbolo inicial da gramática).
A lista de pares (a,b) o que é?
É a lista de produções da gramática. No caso de uma GR num par (a,b), "a"
deve ser um símbolo não-terminal (letra maiúscula) e "b" deve ser um símbolo
terminal seguido ou não de um símbolo não-terminal.
O código feito (classe GramaticaGR) não precisa até então ser modificado, mas
durante a sua fatoração acabamos descobrindo a necessidade de fatorar também o
código de teste, e fatorando o mesmo descobrimos que ele deve ser modificado.
Vamos escrever então um outro teste:
TesteGR01
Ao adicionarmos este teste na Infra-Estrutura de testes (fase amarela), o teste
falha. Assim passamos para a fase vermelha. O teste falhou pois o método
construtor da classe GramaticaRegular ainda não está definido. Escrevendo um
construror que possua os parâmetros desejados, passamos para a fase verde.
FaseVerde02
Agora precisamos fatorar a classe GramaticaGR:
O código feito aparentemente não pode ser simplificado;
O código não parece ter duplicações;
Ok, então vamos para o próximo teste.
TesteGR02?
-- KimieNakahara - 01 Sep 2004
Mas o que é Refactoring?
Refactoring é o processo de alteração do código-fonte de um programa de modo a melhorar sua estrutura interna sem alterar seu comportamento externo. É um modo sistemático de "limpar" o código que minimiza as chances de introdução de bugs. Essencialmente, aplicar refectoring é melhorar o design do código depois que ele foi escrito.
Por que Refactoring
Porque:
* Aprimora o design do software
* Facilita a compreensão do software
* Ajuda a encontrar bugs
* Aumenta a produtividade
Princípios
1 Quando for implementar uma nova funcionalidade em um programa e o código existente não estiver estruturado de forma conveniente à alteração, primeiro refatore o programa, só depois adicione a nova característica.
1 Antes de iniciar um refactoring, esquematize um sólido conjunto de testes, que devem ser auto-verificáveis.
1 Refactoring sempre deve alterar o programa em passos pequenos, assim os erros inseridos são facilmente encontrados.
1 Qualquer um pode escrever código que um computador entende. Bons programadores escrevem código que humanos entendem.
Quando não usar
Refactoring pode ser uma ótima idéia, porém não faz mágica. Se o código em
questão sequer está compilando ou executando de maneira estável, pode ser
melhor recomeçar do zero que tentar consertá-lo. Dependendo do caso pode ser
possível dividir em partes que serão refatoradas e outras que serão
reescritas.
Outra razão para não refatorar é quando o prazo de deadline é muito curto,
pois neste caso a refatoração pode tomar mais tempo que o prazo permite. Uma
possível solução seria refatorar o sistema após sua liberação, pois o custo de
liberá-lo com um refactoring feito às pressas pode ser alto em termos de
manutenção e estabilidade.
No entanto, se não for um caso de deadline, não se deve atrasar a refatoração
por causa de falta de tempo. Experiências com vários projetos mostraram que
refactoring aumenta a produtividade, não ter tempo suficiente é um sinal de
que a refatoração é necessária.
Exemplos de Refactoring
Extract Method
Se não é possível entender rapidamente a lógica de um método...
public void add(Object element){
if (!readOnly){
int new_Size = size + 1;
if (new_Size > elements.length)}
Object[] new_Elements = new Object[elements.lengh + 10];
for(int i = 0; i< size; i++)
new new_Elements[i] = elements[i];
elements = new_Elements;
}
... transforme a lógica em um pequenos passos de mesmo nível de detalhamento que revelem o objetivo do método.
public void add(Object element){
if (readOnly)
return;
if (atCapacity())
grow();
addElement(element);
}
Singleton
Se apenas uma instância da classe for necessária...
public String getNomeCliente(int id){
try{
BancoDados banco = new BancoDados();
String nomeCliente = banco.getNomeCliente();
}catch(Exception e){
//...tratamento de exceção
}
}
...forneça um ponto de acesso único à instância da classe, através do uso do pattern Singleton:
public static BancoDados getInstance(){
return (bancoDados == null) ?
new BancoDados() : bancoDados;
}
private BancoDados(){
//inicializa objeto
//cria conexao, etc
}
Move Method
Quando um método usar mais informações de outra classe do que na qual está inserido...
class Customer{
...
private double amountFor(Rental aRental){
return aRental.getMovie().getPriceCode()*aRental.getDaysRented();
}
}
... transfira o método para a classe à qual ele mais se refere:
class Rental{
double getCharge(){
return getMovie().getPriceCode() * getDaysRented();
}
}
class Customer{
private double amountFor(Rental aRental){
return aRental.getCharge();
}
}
Replace temp with query
Variáveis locais podem ser fáceis de se perder o controle sobre sua funcionalidade - "Para que serve esta variável?", ou de serem "esquecidas" ao longo de alterações, então...
public String execute(HttpServletRequest req, HttpServletResponse response){
try{
HttpSession session= req.getSession();
AcessoBancoDados acessoBd= AcessoBancoDados.getInstance();
ArrayList vetorNomesClientes=
(ArrayList)session.getAttribute("vetorNomesClientes");
acessoBd.setNomesClientes(vetorNomesClientes);
}catch(Exception e){
//trata exceção
}
evite o uso desnecessário de variáveis locais.
public String execute(HttpServletRequest req, HttpServletResponse response){
try{
ArrayList vetorNomesClientes=
(ArrayList)req.getSession().getAttribute("vetorNomesClientes");
AcessoBancoDados.getInstance().setNomesClientes(vetorNomesClientes);
}catch(Exception e){
//trata exceção
}
Chain Constructors
Repetição de código nos construtores prejutica a manutenção do código, pois cada alteração deve ser replicada a todos os construtores
class Pessoa{
private String nome;
private int idade;
private String endereco;
Pessoa(String nome, int idade, String endereco)
{
this.nome = nome;
this.idade = idade;
this.endereco = endereco;
}
Pessoa(String nome, int idade)
{
this.nome = nome;
this.idade = idade;
}
Pessoa(String nome)
{
this.nome = nome;
}
Evite repetição de código nos construtores. Este refactoring é dependente da linguagem, sendo por exemplo, aplicável em Java e não-aplicável em C++.
class Pessoa{
private String nome;
private int idade;
private String endereco;
Pessoa(String nome, int idade, String endereco)
{
this.nome = nome;
this.idade = idade;
this.endereco = endereco;
}
Pessoa(String nome, int idade)
{
this(nome, idade, null);
}
Pessoa(String nome)
{
this(nome, null, null);
}
Referências
* "Refactoring: Improving the Design of Existing Code" de Martin Fowler, editora Addison-Wesley
* http://www.google.com/search?q=refactoring+examples
Material Adicional
What Is Exploratory Testing?
And How It Differs from Scripted Testing
By James Bach
Summary: Exploratory software testing is a powerful and fun approach to testing. In some situations, it can be orders of magnitude more productive than scripted testing. I haven’t found a tester yet who didn’t, at least unconsciously, perform exploratory testing at one time or another. Yet few of us study this approach, and it doesn’t get much respect in our field. It’s high time we stop the denial, and publicly recognize the exploratory approach for what it is: scientific thinking in real time. Friends, that’s a good thing.
Concurrent Test Design and Execution
The plainest definition of exploratory testing is test design and test execution at the same time. This is the opposite of scripted testing (predefined test procedures, whether manual or automated). Exploratory tests, unlike scripted tests, are not defined in advance and carried out precisely according to plan. This may sound like a straightforward distinction, but in practice it’s murky. That’s because “defined” is a spectrum. Even an otherwise elaborately defined test procedure will leave many interesting details (such as how quickly to type on the keyboard, or what kinds of behavior to recognize as a failure) to the discretion of the tester. Conversely, even a free-form exploratory test session will involve tacit constraints or mandates about what parts of the product to test, or what strategies to use. A good exploratory tester will write down test ideas and use them in later test cycles. Such notes sometimes look a lot like test scripts, even if they aren’t.
Exploratory testing is sometimes confused with “ad hoc” testing. Ad hoc testing normally refers to a process of improvised, impromptu bug searching. By definition, anyone can do ad hoc testing. The term “exploratory testing”--coined by Cem Kaner, in Testing Computer Software--refers to a sophisticated, thoughtful approach to ad hoc testing. In the last decade, James Whittaker (at Florida Tech), Cem Kaner, and I have worked to identify the skills and techniques of excellent exploratory testing. For one example of a fully defined and articulated process of exploratory testing, see the General Functionality and Stability Test Procedure for Microsoft’s Windows 2000 Compatibility Certification program. This document is publicly available on Microsoft’s Web site, or on my site at http://www.satisfice.com/tools/procedure.pdf.
Balancing Exploratory Testing with Scripted Testing
To the extent that the next test we do is influenced by the result of the last test we did, we are doing exploratory testing. We become more exploratory when we can’t tell what tests should be run, in advance of the test cycle, or when we haven’t yet had the opportunity to create those tests. If we are running scripted tests, and new information comes to light that suggests a better test strategy, we may switch to an exploratory mode (as in the case of discovering a new failure that requires investigation). Conversely, we take a more scripted approach when there is little uncertainty about how we want to test, when new tests are relatively unimportant, when the need for efficiency and reliability in executing those tests is worth the effort of scripting, and when we are prepared to pay the cost of documenting and maintaining tests.
The results of exploratory testing aren’t necessarily radically different from those of scripted testing, and the two approaches to testing are fully compatible. Companies such as Nortel and Microsoft commonly use both approaches on the same project. Still there are many important differences between the two approaches.
Why Do Exploratory Testing?
Recurring themes in the management of an effective exploratory test cycle are tester, test strategy, test reporting, and test mission. The scripted approach to testing attempts to mechanize the test process by taking test ideas out of a test designer’s head and putting them on paper. There’s a lot of value in that way of testing. But exploratory testers take the view that writing down test scripts and following them tends to disrupt the intellectual processes that make testers able to find important problems quickly.
The more we can make testing intellectually rich and fluid, the more likely we will hit upon the right tests at the right time. That’s where the power of exploratory testing comes in: the richness of this process is only limited by the breadth and depth of our imagination and our emerging insights into the nature of the product under test. In the rapid testing classes at Satisfice, Inc., we have equipment that watches testers invent tests in real-time. When the instructor makes a new suggestion for what to test, or provides new information to the testers about the product, we observe and measure how a roomful of exploratory testers reacts to that information. Free from the encumbrance of predocumentation, they immediately incorporate new ideas into their tests.
Scripting has its place. I can imagine testing situations where efficiency and repeatability are so important that we should script or automate them; for example, in the case where a test platform is only intermittently available, such as a client-server project where there are only a few configured servers available and they must be shared by testing and development. The logistics of such a situation may dictate that we script tests carefully in advance to get the most out of every second of limited test execution time.
Exploratory testing is especially useful in complex testing situations, when little is known about the product, or as part of preparing a set of scripted tests. The basic rule is this: exploratory testing is called for any time the next test you should perform is not obvious, or when you want to go beyond the obvious. In my experience, that’s most of the time.
About the Author James Bach is the founder of Satisfice, Inc., a test training and consulting company. A pioneer in the emerging disciplines of Good Enough quality and exploratory testing, James specializes in expert testing under chaotic conditions. He can be reached at james@satisfice.com.
StickyMinds Weekly Column From 01/29/01
Extreme Programming Links
http://www.extremeprogramming.org/
Usa um diagrama do processo XP como guia de navegação no site (e o site inteiro pode ser adquirido em formato ZIP)
http://www.c2.com/cgi/wiki?ExtremeProgrammingRoadmap
Aqui você pode acompanhar e se envolver em discussões sobre temas quentes de XP
http://www.xprogramming.com/
Sítio do Ron Jeffries (um dos pais de XP). Inclui a revista XP Magazine.
http://www.extremejava.com/
XP com foco em Java. Pouco conteúdo, mas extensa lista de referencias a outros sítios...
http://www.xp2004.org/
A página da Conferencia Anual Européia sobre XP. Muitos links para outros sítios XP.
http://www.xp123.com/
O sítio de William Wake (autor de Extreme Programming—Explored). Muito conteúdo, bons exemplos práticos de fatoração e testes de unidade.
Cetus links
teste2:
Triangulo t1 = new Triangulo(2,2,2);
assert ( t1.éEquilátero()) : "O triangulo (2,2,2) é equilátero";
efeito:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method éEquilátero() is undefined for the type Triangulo
at TrianguloTDD.Testar_Triangulo.main(Testar_Triangulo.java:16)
//Criado em 14/04/2005
package TrianguloTDD;
//Última modificação 14/04/2005 fernando
public class Testar_Triangulo {
public static void main(String argumento[])
{
Triangulo t = new Triangulo(2,3,4);
assert ( t.éEscaleno()) : "O triangulo (2,3,4) é escaleno";
Triangulo t1 = new Triangulo(2,2,2);
assert ( t1.éEquilátero()) : "O triangulo (2,2,2) é equilátero";
assert ( t1.éIsósceles()) : "O triangulo (2,2,2) é isósceles";
System.out.println("OK");
}
}
//Última modificação 14/04/2005 fernando
public class Triangulo {
Triangulo( int l1, int l2, int l3 ){
}
boolean éEscaleno() {
return true;
}
boolean éEquilátero() {
return true;
}
public boolean éIsósceles() {
return true;
}
}
Acrescentado o código de teste:
Triangulo t2 = new Triangulo( 4,4,7);
assert (t2.éIsósceles()) :"é isósceles o triângulo (4,4,7)";
que funcionou imediatamente, sem mais modificações.
(isso de funcionar sem precisar código novo pode não ser bom sinal, mas nesse caso já haviamos testado o resultado da função, este teste é mais para cercar efeitos laterais)
Triangulo t2 = new Triangulo( 4,4,7); assert (t2.éIsósceles()) :"é isósceles o triângulo (4,4,7)";
com a introdução do novo teste:
assert (false == t2.éEquilátero()) :"NÃO é equilátero o triângulo (4,4,7)";
ocorre o erro:
Exception in thread "main" java.lang.AssertionError: NÃO é equilátero o triângulo (4,4,7)
at TrianguloTDD.Testar_Triangulo.main(Testar_Triangulo.java:23)
Já tinhamos:
Triangulo t2 = new Triangulo( 4,4,7);
Introduzindo o teste:
assert (false == t2.éEscaleno()) :"NÃO é escaleno o triângulo (4,4,7)";
Ocorre a exceção:
Exception in thread "main" java.lang.AssertionError: NÃO é escaleno o triângulo (4,4,7)
at TrianguloTDD.Testar_Triangulo.main(Testar_Triangulo.java:24)
teste8: "NÃO é equilátero o triângulo (2,3,-4)"
Introduzimos o teste:
Triangulo t3 = new Triangulo (2,3,-4);
assert (false == t3.éEquilátero()) :"NÃO é equilátero o triângulo (2,3,-4)";
Compilamos. Nenhum problema.
Rodamos. Nenhum problema.
O Quê??
package TrianguloTDD;
public class Testar_Triangulo {
public static void main(String argumento[])
{
Triangulo t = new Triangulo(2,3,4);
assert ( t.éEscaleno()) : "O triangulo (2,3,4) é escaleno";
System.out.println("OK");
}
}
package TrianguloTDD;
public class Triangulo {
Triangulo( int l1, int l2, int l3 ){}
boolean éEscaleno() {
return true;
}
}
Classe Testa_Gramatica
package cd01;
public class Testa_Gramatica {
public static void main(String[] args) {
GramaticaRegular umaGramatica = new GramaticaRegular();
assert (umaGramatica.ehRegular()) : "A gramática em questão não é regular";
}
}
Classe Gramatica-Regular
package cd01;
public class GramaticaRegular {
public boolean ehRegular() {
return true;
}
}
Classe Testa_Gramatica
package cd02;
public class Testa_Gramatica {
public static void main(String[] args) {
char[] vn = new char[4];
vn[0] = 'S';
vn[1] = 'A';
vn[2] = 'B';
vn[3] = 'C';
char[] vt = new char[2];
vt[0] = 'a';
vt[1] = 'b';
String[] p = new String[12];
p[0] = new String("(S,bA)");
p[1] = new String("(S,aB)");
p[2] = new String("(S,b)");
p[3] = new String("(S,'')"); // epsolon seria o caracter vazio
p[4] = new String("(A,aB)");
p[5] = new String("(A,bA)");
p[6] = new String("(A,b)");
p[7] = new String("(B,bB)");
p[8] = new String("(B,aC)");
p[9] = new String("(C,bC)");
p[10] = new String("(C,aA)");
p[11] = new String("(C,a)");
char s = 'S';
GramaticaRegular umaGramatica = new GramaticaRegular(vn,vt,p,s);
assert (umaGramatica.ehRegular()) : "A gramática em questão não é regular";
}
}
Classe Gramatica-Regular
package cd02;
public class GramaticaRegular {
public GramaticaRegular(char[] vn,char[] vt,String[] p,char s) {
}
public boolean ehRegular() {
return true;
}
}
Com éIsósceles retornando sempre true, não há como dar falso mesmo...
Então fazemos um novo éIsósceles:
public boolean éIsósceles() {
return _l1==_l2 || _l2==_l3 || _l1==_l3 ; //"pelo menos dois lados são iguais"
}
Para evitar passagem de parâmetros, usamos variáveis de instância.
O código completo ficou assim:
//Criado em 14/04/2005
package TrianguloTDD;
//Última modificação 14/04/2005 fernando
public class Testar_Triangulo {
public static void main(String argumento[])
{
Triangulo t = new Triangulo(2,3,4);
assert ( t.éEscaleno()) : "O triangulo (2,3,4) é escaleno";
Triangulo t1 = new Triangulo(2,2,2);
assert ( t1.éEquilátero()) : "O triangulo (2,2,2) é equilátero";
assert ( t1.éIsósceles()) : "O triangulo (2,2,2) é isósceles";
assert (false == t.éIsósceles()) :"NÃO é isósceles o triângulo (2,3,4)";
System.out.println("OK");
}
}
//Criado em 14/04/2005
package TrianguloTDD;
//Última modificação 14/04/2005 fernando
public class Triangulo {
int _l1, _l2,_l3;
Triangulo( int l1, int l2, int l3 ){
_l1 = l1;
_l2 = l2;
_l3 = l3;
}
boolean éEscaleno() {
return true;
}
boolean éEquilátero() {
return true;
}
public boolean éIsósceles() {
return _l1==_l2 || _l2==_l3 || _l1==_l3 ; //"pelo menos dois lados são iguais"
}
}
A modificação abaixo faz passar o teste:
boolean éEquilátero() {
return _l1==_l2 && _l2==_l3 ; //"todos os lados são iguais entre si"
}
Introduzindo uma nova versão para éEscaleno,
boolean éEscaleno() {
return _l1 != _l2 && _l2 !=_l3 && _l1 !=_l3 ; // nenhum lado igual a outro
}
o teste passa a funcionar
package TrianguloTDD;
public class Testar_Triangulo {
public static void main(String argumento[])
{
Triangulo t = new Triangulo(2,3,4);
assert ( t.éEscaleno()) : "O triangulo (2,3,4) é escaleno";
System.out.println("OK");
}
}
package TrianguloTDD;
public class Triangulo {
Triangulo( int l1, int l2, int l3 ) {}
boolean éEscaleno() {
return false;
}
}
Com a introdução do teste2, bastou introduzir o método éEquilátero para passar batido:
boolean éEquilátero() {
return true;
}
assert (false == t.éIsósceles()) :"NÃO é isósceles o triângulo (2,3,4)";
---
Exception in thread "main" java.lang.AssertionError: NÃO é isósceles o triângulo (2,3,4)
at TrianguloTDD.Testar_Triangulo.main(Testar_Triangulo.java:19)
Como vimos, o teste passou, meio sem querer...
Isso pode ser um mau sinal. Normalmente, em TDD fazemos teste para puxar código (uma vez que não se escreve código nenhum sem testes).
Então, se um teste não puxa código, ou o código já existe, e o teste pode ser desnecessário, ou o teste não deveria passar (era o que esperávamos)
Nesse caso específico, desejamos que a chamada não seja aceita, por não representar um uso válido. Usaremos pré-condições pra isso.
Ou seja: o que está sendo testado aqui não é a classificação de um triângulo, mas a possibilidade de criar um triângulo inválido usando nosso módulo ("no pasaran!" :-)
OsTextos
AsApresentacoes
MaquinaTelis
Observando o Código atual, vemos que, a cada vez que executamos uma das funções de classificação:
boolean éEscaleno() {
return contarIgualdades() == 0 ;
}
boolean éEquilátero() {
return contarIgualdades() == 3 ;
}
public boolean éIsósceles() {
return contarIgualdades() > 0;
}
estamos, no fundo, apenas repetindo a execução de:
private int contarIgualdades(){
if (a == b) igualdades++;
if (a == c) igualdades++;
if (b == c) igualdades++;
return igualdades;
Continuando a observar o código, vemos também que não há como mudar os lados de um triângulo. Isso é normal nesse caso, em que os requisitos exigem somente uma classificação quanto aos lados..
Mas, se um triângulo não pode ser modificado, podemos executar essa função apenas uma vez, no construtor da classe:
Triangulo( int l1, int l2, int l3 ){
a = l1;
b = l2;
c = l3;
igualdades = contarIgualdades();
}
Podemos assim trocar as chamadas da função contarIgualdades() por um acesso direto à variável igualdades:
boolean éEscaleno() {
return igualdades == 0 ;
}
boolean éEquilátero() {
return igualdades == 3 ;
}
public boolean éIsósceles() {
return igualdades > 0;
}
Para repercutir essa decisão, vamos fazer com que as variáveis representando os lados sejam qualificadas como final.
O código da classe agora está assim:
public class Triangulo {
final int a, b,c;
int igualdades = 0;
Triangulo( int l1, int l2, int l3 ){
a = l1;
b = l2;
c = l3;
igualdades = contarIgualdades();
}
boolean éEscaleno() {
return igualdades == 0 ;
}
boolean éEquilátero() {
return igualdades == 3 ;
}
public boolean éIsósceles() {
return igualdades > 0;
}
private int contarIgualdades(){
if (a == b) igualdades++;
if (a == c) igualdades++;
if (b == c) igualdades++;
return igualdades;
}
}
Fatorar o código de testes?
Sim... se não há nenhuma garantia de que sejamos infalíveis em nosso código de produção (porisso usamos os testes)
então quem garante que não erramos em nosso código de testes?
O que nos está trancando, objetivamente, é o fato que, na verdade, não temos mais testes rodando. Nossos dois últimos testes apenas derrubam o software. Qual o problema?
O problema é simples: passamos a usar pré-condições em nosso código de produção (classe Triangulo).
Isso significa o estabelecimento de um contrato com nossos clientes: só aceitaremos lados válidos. Em troca, nunca construiremos triangulos inválidos, e permitimos a classificação do triangulo.
Cabe a nossos clientes cuidar de obedecer as pré-condições. E aqui foi nossa falha: nosso código de testes é um cliente de Triângulo, e não está cumprindo o contrato.
Que fazer?
Vamos reescrever o teste...
O teste atual está escrito como:
Triangulo t3 = new Triangulo (2,3,-4);
assert (false == t3.éEquilátero()) :"NÃO é equilátero o triângulo (2,3,-4)";
e isso derruba o software, pois o cliente (nossa classe de testes) não respeita o contrato.
O que deveríamos realmente testar era:
"Se for feita tentativa de criar triangulo com algum lado negativo, deve ser gerada uma exceção com a mensagem ' Lados devem ter valores positivos' "
Como testar isso? Capturando o AssertionError gerado pelo triangulo:
try {
t = new Triangulo(2, 3, -4);
} catch (AssertionError ae) {
assert (ae.getMessage().equals("Lados devem ter valores positivos"));
}
Nosso código de Testes agora ficou assim:
//Criado em 14/04/2005
package TrianguloTDD;
//Última modificação 14/04/2005 fernando
public class Testar_Triangulo {
public static void main(String argumento[]) {
Triangulo t = new Triangulo(2, 3, 4);
assert (t.éEscaleno()) : "O triangulo (2,3,4) é escaleno";
Triangulo t1 = new Triangulo(2, 2, 2);
assert (t1.éEquilátero()) : "O triangulo (2,2,2) é equilátero";
assert (t1.éIsósceles()) : "O triangulo (2,2,2) é isósceles";
assert (false == t.éIsósceles()) : "NÃO é isósceles o triângulo (2,3,4)";
Triangulo t2 = new Triangulo(4, 4, 7);
assert (t2.éIsósceles()) : "é isósceles o triângulo (4,4,7)";
assert (false == t2.éEquilátero()) : "NÃO é equilátero o triângulo (4,4,7)";
assert (false == t2.éEscaleno()) : "NÃO é escaleno o triângulo (4,4,7)";
try {
t = new Triangulo(2, 3, -4);
} catch (AssertionError ae) {
assert (ae.getMessage().equals("Lados devem ter valores positivos"));
}
try {
t = new Triangulo(2, 3, 100);
} catch (AssertionError ae) {
assert (ae.getMessage().equals("Violadas as Desigualdades Triangulares"));
}
System.out.println("OK");
}
}
Fedores & Fatores
| Fedor | Descrição | Fatoração |
| Código Duplicado | Repetições de trechos de código | Extrair agenda |
| Nome inconsistente | Use nomes consistentes | Renomear agenda |
| Código Morto | Uma variável, agenda, parâmetro, pedaço de código, modelo, etc. não está sendo utilizado em nenhum lugar | Remover o código |
| Obsessão das Primitivas | Uso de primitivas em excesso (deixam o código confuso) | Extrair Agenda |
| Nome não-comunicativo | Escolha nomes que comuniquem a intenção (use o melhor nome que puder no momento, depois você muda, se necessário) | Renomear o elemento |
| Agenda Longa | Quanto mais longa a agenda pior pra se saber o que é que está acontecendo | Extrair Agenda |
| Comentário | Tendência a verborragia. Reduz a clareza do código. Usar comentário somente pra dizer "o porque" (e não "o que" ou "como") | Extrair Agenda / Renomear Agenda ou Variável / Introduzir Asserções |
| Modelo "metido" | Modelo longo, tentando fazer muita coisa (normalmente com muitas variáveis) | Extrair Modelo |
| Modelos com mesmo trecho de código | Dois ou mais modelos com trecho comum de código | Extrair Molde (criar Modelo Abstrato) |
| Modelo "invejoso" | Modelo que faz coisas que são de responsabilidade de outro | Extrair Modelo |
Tecnicas de Fatoração
| Tecnicas de Fatoração | Descrição | Localização livro Fowler |
| Extrair métodos | Decompor métodos grandes em partes menores, criando pequenos métodos e passando variaveis locais como parâmetro. | p.18 |
| Mover métodos | Colocar os métodos nas classes mais adequadas. Os dados usados no método, devem pertencer a classe onde ele se encontra. | p.22 |
| Trocar variáveis temporárias por métodos | Variáveis temporárias podem se tornar um problema, geralmente elas estão situadas em rotinas longas e complexas. | p.30 |
| Polimorfismo em comandos condicionais | Os atributos de um comando condicional deve pertencer a classe onde o comando se encontra. | p.35 |
-- RodrigoPavezi - 15 Jun 2005
Ferramentas para XP
Introdução
Atualmente existem variados tipos te ferramentas para auxiliar XP. Cada tipo com sua especialidade, assim temos as ferramentas para testes de unidades, testes de aceitação, planejamento, acompanhamento e teste de performance dos projetos.
É necessário usar ferramentas?
As ferramentas criadas para o auxilio a XP são de boa qualidade e muito bem feitas em sua maioria. Mas não se deve limitar-se unicamente a elas, pois a equipe poderá se desvincular dos conceitos básicos de XP. Onde elas substituem algumas formas de trabalho que XP prega.
O que usar então?
As equipes podem trabalhar unidas utilizando o quadro branco e os cartazes grudados nas paredes. Assim fazendo com que todos se evolvam por igual com o projeto.
Com a utilização de ferramentas pode acontecer de uma pessoa da equipe trabalhar com a ferramenta e os outros integrantes da equipe simplesmente ver o que foi feito, assim não tendo a comunicação entre a equipe. Esse é caso em que se foge de um dos princípios de XP, que é a comunicação.
Utilizando cartazes
Exemplo de um cartaz que mostra a quantidade de testes, e se eles estão todos trabalhando. Para cada período de tempo(dias, semanas, ou interações) quantos testes de aceitação do cliente existem. Em verde é a quantidade que está trabalhando, e em vermelho é a quantidade que não está trabalhando. O cartaz mostra o que você pode ver em um projeto com uma ordem progressiva de teste rodando.
Se o vermelho estiver diminuindo significa que as coisas estão indo bem.
No gráfico baixo alguma coisa não está indo bem, um grande bloco de testes começou a falhar, mas ainda esta tendo alguma melhora. O que se pode fazer é pedir ajuda a equipe para tomar alguma iniciativa a respeito do problema.

Então as ferramentas são inúteis?
Não, elas são ferramentas que devem ser usadas como complemento, ou seja como auxilio, não tornando-as fundamentais para a aplicação de XP nos projetos.
Ron Jeffries
“And I wish you would try working without them before you try working with them.”
Algumas ferramentas:
Como já foi dito temos ferramentas para testes de unidades, testes de aceitação, planejamento, acompanhamento e teste de performance dos projetos.
Ferramentas para planejamento e acompanhamento: são ferramentas, como o próprio nome diz, que auxiliam os desenvolvedores, e principalmente os gerenciadores, com os seus projetos.Temos como exemplo:
Ferramentas para testes de unidade: são ferramentas para testar as unidades do projeto, sendo constantemente usadas no decorrer do mesmo. Atualmente existem diversas ferramentas para cada linguagem de programação.Temos como exemplo:
Ferramentas para teste de aceitação: são ferramentas para se fazer o teste generalizado do projeto, sendo mais ou menos como o teste de um conjunto de testes de unidade.Temos como exemplo:
Ferramentas para testes de performance: são ferramentas que testam performance dos teste de unidades, sendo testado os tempos dos testes e das interações.Temos como exemplo:
Conclusão
Conclui com minhas pesquisas que as ferramentas de auxilio a XP são de grande ajuda para as equipes e seus projetos. Mas só devem ser utilizadas por equipes que já tenham um grande conhecimento e um bom hábito com as regras do XP.
Bibliografia:
Grupo Seis e Oito
Michel Zanini
Thiago Napoleao
-------------------------
Teste
-------------------------
import junit.framework.TestCase;
public class TrianguloTest extends TestCase {
Triangulo triangulo;
public TrianguloTest() {
triangulo = new Triangulo();
}
public void testeQualForma() {
try {
triangulo.setLado1(2);
triangulo.setLado2(1);
} catch (Exception e) {
e.printStackTrace();
}
boolean passou = false;
try {
triangulo.setLado3(-3);
} catch (Exception e1) {
passou = true;
}
assertTrue(passou);
assertEquals(triangulo.qualForma(),"isoceles");
try {
triangulo.setLado3(3);
} catch (Exception e) {
e.printStackTrace();
}
assertEquals(triangulo.qualForma(),"escaleno");
try {
triangulo.setLado1(3);
triangulo.setLado2(3);
} catch (Exception e) {
e.printStackTrace();
}
assertEquals(triangulo.qualForma(),"equilatero");
}
}
-------------------------------------------------
Classe
-------------------------------------------------
public class Triangulo {
private double lado1;
private double lado2;
private double lado3;
public Triangulo() {
try {
setLado1(1);
setLado2(1);
setLado3(1);
} catch (Exception e) {
e.printStackTrace();
}
}
public Triangulo(double l1, double l2, double l3) {
try {
setLado1(l1);
setLado2(l2);
setLado3(l3);
if (!validaTriangulo())
throw new Exception("Triangulo Invalido");
} catch (Exception e) {
e.printStackTrace();
}
}
public double getLado1() {
return lado1;
}
public double getLado2() {
return lado2;
}
public double getLado3() {
return lado3;
}
public void setLado1(double l1) throws Exception {
if (l1 > 0)
lado1 = l1;
else
throw new Exception("Lado Negativo ou Nulo");
}
public void setLado2(double l2) throws Exception {
if (l2 > 0)
lado2 = l2;
else
throw new Exception("Lado Negativo ou Nulo");
}
public void setLado3(double l3) throws Exception {
if (l3 > 0)
lado3 = l3;
else
throw new Exception("Lado Negativo ou Nulo");
}
private boolean validaTriangulo() {
boolean ehValido = true;
if (lado1 > (lado2 + lado3))
ehValido = false;
else if (lado2 > (lado1 + lado3))
ehValido = false;
else if (lado3 > (lado1 + lado2))
ehValido = false;
return ehValido;
}
public String qualForma() {
if (!validaTriangulo())
return "Triângulo inválido";
final String ISO = "isoceles";
final String ESC = "escaleno";
final String EQU = "equilatero";
if ((lado1 == lado2) & (lado2 == lado3)) {
return EQU;
} else if ((lado1 == lado2) || (lado2 == lado3) || (lado1 == lado3)) {
return ISO;
} else {
return ESC;
}
}
}
%STARTINCLUDE%
<style>
body {
margin: 5px;
padding: 0px;
font-family: verdana,arial,sans-serif;
font-size: 12px;
}
a {
color: #336699;
text-decoration:none;
}
a:hover {
text-decoration:underline;
}
h2 {
color: #336699;
font-size: 16px;
}
.menuHorizontal {
width: auto;
margin: 0px;
padding: 5px;
text-align: left;
border-top: 1px solid gray;
border-bottom: 1px solid gray;
margin-bottom:25px;
}
.menuHorizontal li{
font-size: 12px;
display: inline;
}
.menuHorizontal li a {
padding: 5px;
color: black;
}
#edugraf{
color: gray;
font-size: 10px;
text-align: center;
padding: 2px;
margin: 0px;
}
h1,h2 {
margin-bottom:2px;
padding:0px;
}
#cabecalho img {
margin: 0px;
float: right;
}
#cabecalho {
margin-left:0px;
margin-right:0px;
margin-bottom: 20px;
}
#menuDoTWiki {
clear:left;
border-top: 1px solid silver;
border-bottom: 1px solid silver;
text-align: right;
padding: 3px;
margin: 0px;
}
.menu {
clear: left;
float: left;
width: 100px;
margin-top: 0.5em;
background: #fff;
padding-top: 0.2em;
padding-left: 0.2em;
padding-right: 0.2em;
padding-bottom: 0px;
border: solid gray 1px;
}
.menu a, .menu span {
display: block;
border: none;
margin-bottom: 0.2em;
padding: 0.2em;
}
.menu a {
background: %WEBBGCOLOR%;
color: black;
text-decoration: none;
}
.menu a:hover {
background: white ;
color: black;
border: none;
}
#principal {
margin-left: 140px;
padding: 0.5em;
text-align: justify;
}
#PreviewNote {
border: 2px dashed #CC0000;
color: #CC0000;
background: #FFFFCC;
font-size: 14px;
padding: 5px;
text-align: center;
margin-bottom: 10px;
}
#caminho {
border-bottom: 1px solid grey;
border-top: 1px solid grey;
background: silver;
padding-top: 2px;
padding-bottom: 2px;
}
#título {
background: %WEBBGCOLOR%;
border-bottom: 1px solid grey;
border-top: 1px solid grey;
}
#rodape {
clear: left;
border-top: 1px solid grey;
border-bottom: 5px solid %WEBBGCOLOR%;
}
#título, #caminho {
padding-left: 5px;
}
</style>
%STOPINCLUDE%
-- AndersonNielson - 27 Jul 2004
- DSC03533.JPG:
- DSC03534.JPG:
- DSC03535.JPG:
- DSC03531.JPG:
- DSC03532.JPG:
%STARTINCLUDE%
<div id="anexos">
%META{"attachments"}%
</div>
</div>
<div id="rodape"></div>
<div id="menuDoTWiki" class="%WIKINAME%">
<a accesskey="E" href='%SCRIPTURLPATH%/edit%SCRIPTSUFFIX%/%INCLUDINGWEB%/%INCLUDINGTOPIC%?t=%GMTIME{"$year$mo$day$hour$min$sec"}%'><img src="%ATTACHURL%/edit.png" border="0" title="Editar este Tópico" alt="Editar"/></a>
<a accesskey="A" href='%SCRIPTURLPATH%/attach%SCRIPTSUFFIX%/%INCLUDINGWEB%/%INCLUDINGTOPIC%?t=%GMTIME{"$year$mo$day$hour$min$sec"}%'><img src="%ATTACHURL%/attach.png" border="0" title="Anexar um arquivo a este Tópico" alt="Anexar arquivo"/></a>
<a accesskey="V" href="%SCRIPTURLPATH%/rdiff%SCRIPTSUFFIX%/%INCLUDINGWEB%/%INCLUDINGTOPIC%" title="Versões"><img src="%ATTACHURL%/diff.png" border="0" title="Versões deste Tópico" alt="Versões"/></a>
<a accesskey="P" href="%SCRIPTURLPATH%/view/%INCLUDINGWEB%/ProjetoGrafico"><img src="%ATTACHURL%/graph.png" border="0" title="Projeto Gráfico" alt="Projeto Gráfico"/></a>
<a accesskey="M" href="%SCRIPTURLPATH%/oops%SCRIPTSUFFIX%/%INCLUDINGWEB%/%INCLUDINGTOPIC%?template=oopsmore¶m1=1.2¶m2=1.2"><img src="%ATTACHURL%/properties.png" border="0" title="Mais..." alt="Mais..."/></a>
</div>
<div id="edugraf">
E D U G R A F - Laboratório de Software Educacional - UFSC - CTC - INE <br/>
Campus Universitário - Trindade, Florianópolis, SC, Brasil 88040-090<br/>
Fone: +55 48 331 9735 / Fax: +55 48 331-9770
</div>
<!--
<div id="icones">
<a href="http://validator.w3.org/check?uri=referer">
<img src="http://twiki.softwarelivre.org/pub/Main/FreeSkinPreTopic/valid-xhtml10.png"/>
</a>
<img src="http://twiki.softwarelivre.org/pub/Main/FreeSkinPreTopic/validcss.png"/>
<img src="http://twiki.softwarelivre.org/pub/Main/FreeSkinPreTopic/twiki_powered.png" alt="TWiki powered"/>
</div>
-->
</body>
</html>
%STOPINCLUDE%
%STARTINCLUDE%
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
<head>
<title>XP : %INCLUDINGTOPIC%</title>
%INCLUDE{"FolhaDeEstilo"}%
</head>
<body>
<div id="cabecalho">
<h1 id="título">XP : <nop>%INCLUDINGTOPIC%</h1>
<div id="caminho">
[[http://xp.edugraf.ufsc.br/][%WIKITOOLNAME%]] » [[%INCLUDINGWEB%.%HOMETOPIC%][%INCLUDINGWEB%]]%META{"parent" prefix=" » " separator=" » " }% » %INCLUDINGTOPIC%
</div>
</div>
<div class="menu">
%WEBTOPICLIST%
</div>
<div id="principal">
%STOPINCLUDE%
-- DaxBogo - 29 Mar 2005
EquipeCinco
CodigoTriangulo
ErroPrograma
NossaEquipe2
NossoCodigo2
-- AndreChinvelski - 29 Mar 2005
Andre Chinvelski
Leonardo Garcia
Michel Zanini e Rodrigo Pavezi
public class Triangulo {
public String qualForma( int x, int y, int z ) {
final String ISO = "isoceles";
final String ESC = "escaleno";
final String EQU = "equilatero";
if ( (x == y) & (x == z) ) {
return EQU;
} else if ( (x == y) || (y == z) || (z == x) ) {
return ISO;
} else {
return ESC;
}
}
}
Teste---------------------------------------------------------------------------------------
import junit.framework.TestCase;
public class TrianguloTest extends TestCase {
Triangulo triangulo;
public TrianguloTest() {
triangulo = new Triangulo();
}
public void testeQualForma() {
int x = 2;
int y = 3;
int z = 3;
assertEquals(triangulo.qualForma(x,y,z),"isoceles");
z = 5;
assertEquals(triangulo.qualForma(x,y,z),"escaleno");
x = 5;
y = 5;
assertEquals(triangulo.qualForma(x,y,z),"equilatero");
}
}
A EquipeSeis utilizou a classe acima com o seguinte programa:
Triangulo triangulo = new Triangulo();
String equilatero,isoceles,escaleno;
equilatero = triangulo.qualForma(12.4,12.4,12.4);
e apontou um erro ao utilizar lados com medidas não inteiras.
public class Triangulo {
private double lado1;
private double lado2;
private double lado3;
public Triangulo() {
setLado1(1);
setLado2(1);
setLado3(1);
}
public Triangulo(double l1, double l2, double l3) {
setLado1(l1);
setLado2(l2);
setLado3(l3);
}
public double getLado1() {
return lado1;
}
public double getLado2() {
return lado2;
}
public double getLado3() {
return lado3;
}
public void setLado1(double l1) {
if (l1 > 0)
lado1 = l1;
}
public void setLado2(double l2) {
if (l2 > 0)
lado2 = l2;
}
public void setLado3(double l3) {
if (l3 > 0)
lado3 = l3;
}
private boolean validaTriangulo() {
boolean ehValido = true;
if (lado1 > (lado2 + lado3))
ehValido = false;
else if (lado2 > (lado1 + lado3))
ehValido = false;
else if (lado3 > (lado1 + lado2))
ehValido = false;
return ehValido;
}
public String qualForma() {
if (!validaTriangulo())
return "Triângulo inválido";
final String ISO = "isoceles";
final String ESC = "escaleno";
final String EQU = "equilatero";
if ((lado1 == lado2) & (lado2 == lado3)) {
return EQU;
} else if ((lado1 == lado2) || (lado2 == lado3) || (lado1 == lado3)) {
return ISO;
} else {
return ESC;
}
}
}
Teste
--------------------------------------------------------------------------------------------------------------
import junit.framework.TestCase;
public class TrianguloTest extends TestCase {
Triangulo triangulo;
public TrianguloTest() {
triangulo = new Triangulo();
}
public void testeQualForma() {
triangulo.setLado1(2);
triangulo.setLado2(1);
triangulo.setLado3(-3);
assertEquals(triangulo.qualForma(),"isoceles");
triangulo.setLado3(3);
assertEquals(triangulo.qualForma(),"escaleno");
triangulo.setLado1(3);
triangulo.setLado2(3);
assertEquals(triangulo.qualForma(),"equilatero");
}
}
-- AndreChinvelski - 29 Mar 2005
GrupoIntegrantes
CodigoAntigo
ComentarioGrupo5
NovoCodigo
NovoGrupo
-- LeonardoGarcia - 05 Apr 2005
NovoCodigo
NovoGrupo
O método do grupo aceita Zero e Numeros negativos.
Michel e Rodrigo.
EquipeSeis
public class ClassificaTriangulo {
public ClassificaTriangulo() {
}
public String classifica(float l1, float l2, float l3) {
if(l1==l2 && l2==l3)
return "Equilatero";
else if((l1==l2 && l1!=l3) || (l2==l3 && l3!=l1) || (l1==l3 && l3!=l2) )
return "Isoceles";
else
return "Escaleno";
}
}
EquipeA7
CodigoEquipe7
grupo foi fechado, integrantes uniram-se ao grupo Cinco
Grupo1 : Diego Machado
Mateus Ludwich
Rafael Ferreira
class Programa {
public static void main (String args[]) {
Triangulo umTriangulo;
umTriangulo = new Triangulo(2,2,6);
if (umTriangulo.ehEquilatero())
System.out.println("Equilatero");
else
if (umTriangulo.ehIsoceles())
System.out.println("Isoceles");
else
System.out.println("Escaleno");
}
}
ClasseTriangulo
Os grupos um e dois se uniram e desenvolveram juntos uma solução que corrigia e melhorava as soluções anteriores.
NovaClasseTriangulo
ProgramaTesteDaClasse
ConsideracoesCincoSeteOito
package TrianguloTDD;
public class Testar_Triangulo {
public static void main(String argumento[])
{
// teste vai aqui. se não funcionar, gera exceção
// se funcionar:
System.out.println("OK");
}
}
Integração Contínua
Os times de Programação Radical mantém o sistema completamente integrado todo o tempo. Dizemos até que um "build" diário é muito pouco: os times XP integram o sistema várias vezes ao dia (uma equipe XP de quarenta pessoas faz pelo menos umas oito ou dez integrações a cada dia!)
O benefício dessa prática pode ser visto se visto se você pensar em projetos anteriores que você pode ter ouvido falar, ou mesmo ter tomado parte, e onde o processo de integração era semanal ou até mais frequente, e que usualmente levava ao "inferno da integração", onde tudo deixava de funcionar e ninguem sabia porquê.
Integração não frequente leva a sérios problemas num projeto de software. Em primeiro lugar, embora a integração seja crítica para distribuir um bom código funcionando, o time não tem essa prática, e a tarefa é frequentemente delegada a pessoas que não estão familiarizadas com todo o sistema. Em segundo lugar, código integrado raramente é muitas vezes - eu diria usualmente - código com problemas.Os problemas pipocam na hora da integração, problemas que não foram detectados por nenhum dos testes que tiveram lugar no sistema não integrado. Em terceiro lugar, processos fracamente integrados levam a longos períodos de congelamento do código. Código congelado significa que voce tem longos períodos de tempo em que os programadores podem estar trabalhando em características importantes para a distribuição, mas estas características precisam ser levadas pra trás. Isso enfraquece sua posição no mercado, ou com seus usuários finais.
-- ThiagoMoreira - 30 Nov 2004
- ic.ppt: Integração Continua: um estudo de caso
Motivação
A seguir são listados alguns dos motivos que me levaram a implantar integração continua na empresa que atualmente trabalho.
- Curiosidade pelo assunto.
- Grande dependência entre os projetos.
- Incompatibilidade entre projetos.
Pesquisas
Depois de ler o livro “Extreme Programming Guia Prático” especialmente o capítulo referente a integração continua, observei que as práticas ali descritos no capítulo poderiam servir perfeitamente para solucionar problemas que enfrentávamos em nossa empresa. Tudo isso porque as incompatibilidade entre os projetos da empresa só eram detectadas no cliente. O que causava aborrecimentos tanto no cliente como na área de suporte que é responsável pela assistência ao cliente.
Após uma breve pesquisa e além das dicas fornecidas no livro optei por utilizar o projeto Jakarta Gump, como o gerenciador de integração continua. Ele é um projeto open-source hospedado e matindo pela fundação Apache.
Problemas
O primeiro passo para implantar a integração continua na empresa foi ter a permição para pesquisar e desenvolver estratégias para implantação dos gerentes. Mas convencer um gerente de TI ou até mesmo um grupo de gerentes de TI não é nada fácil e eu precisa convencer um grupo deles. Minha estratégia foi convencer um e depois os outros e foi isso que fiz e deu certo. No entanto, mesmo com eles convencidos, não tive plena liberdade para pesquisar e desenvolver minha estratégia. Tive que utilizar de meus horários vagos e após os expediente para trabalhar no projeto.
Outro fator que não ajudou, foi a falta de um equipamento (um computador) para instalar e executar o Jakarta Gump, tive que utilizar um servidor que já estava sobre carregado.
Implantação
Como nossa empresa possui diversos projetos sendo desenvolvidos em paralelo e integrados, segui um velho ditado: "Dividir para conquistar", optei por integrar somente dois projetos e obtendo sucesso, fazer a integração dos outros. No entanto escolhi os dois projetos mais complicados que possuimos, para realizar os testes.
Um dos projetos é um conjunto de classes utilitárias, responsáveis pelo acesso à contexto JNDI, formatação e parse de datas, etc... O outro projeto é o coração do sistema, responsável por toda iteração com o banco de dados e representação das entidades do software, para isso utlizando da tecnologia EJB. Esse segundo projeto depende do primeiro em varios aspectos. Por esse motivo escolhi esses projetos.
A integração foi configurada no Gump e era executada todo dia para esses dois projetos.
Conclusões
O propósito do projeto nunca foi alcançado, que era integrar e eliminar incompatibilidade entres os projetos. Atualmente o projeto foi cancelado. Algumas conclusões pude tirar, entre elas estão:
- Integração continua de programas J2EE é difícil:
- Dependência de servidor de aplicação.
- Montar ambiente (base de dados).
- A falta de apoio efetivo dos gerentes, pode arruinar qualquer projeto.
- Projetos muitos complexos levam tempo, consequentemente dinheiro, para serem integrados.
- Pouco tempo para dedicar-se à projeto pode arruinar o mesmo.
Introdução ao Eclipse
Aqui estamos colocando material para introdução ao Eclipse.
-- AndersonNielson - 19 Aug 2004
Introdução ao TWiki
Aqui estamos colocando material para introdução ao TWiki.
-- AndersonNielson - 19 Aug 2004
-- MeLga - 16 Aug 2004
-- AndreGermanoRegert - 22 Apr 2005
No tradutor do Google, só é possivel traduzir de
português para inglês a palavra isósceles.
Não é o melhor dicionário, mas é um começo...
JThreadUnit
Problema clásico de sincronismo, especialmente os que ocorrem na alocação de recursos em um sistema operacional. O problema é definido assim:
Existem 5 filósofos sentados em volta de uma mesa de jantar. Entre cada par adjacente de filósofos há um pauzinho de comer. Assim, existem 5 pauzinhos. Cada filósofo faz duas coisas: pensar e comer. O filósofo pensa por um tempinho, e então pára de pensar, fica com fome. Quando o filósofo fica com fome, ele não pode comer enquanto não estiver de posse do pauzinho da sua direita e do pauzinho da esquerda. Quando o filósofo acabar de comer, ele solta os pauzinhos e volta a pensar.
enciclopédia
-- MeLga - 28 Sep 2004
-- AndreGermanoRegert - 26 Jun 2005
Alunos:
- André Germano Regert
- Jader Wallauer
Jogo Batalha Naval
Descrição do jogo:
Batalha Naval é um clássico jogo de tabuleiro para dois jogadores, onde cada jogador possui uma frota de navios e vence quem afundar a frota adversária primeiro.
O tabuleiro é formado por quatro matrizes ou tabelas de marcação, onde cada jogador enxerga somente duas. Uma delas é utilizada para posicionar a frota, e outra para marcar os pontos de ataque a frota adversária.
Cada frota de navios consiste de 4 Rastreadores, 3 Fragatas, 2 Cruzadores, e 1 Encouracado. Cada navio ocupa espaços consecutivos no tabuleiro, na horizontal ou na vertical, de acordo com a lista abaixo:
- Encouraçado - 5 casas
- Cruzador - 4 casas
- Fragata - 3 casas
- Rastreador - 2 casas
No inicio do jogo, cada jogador posiciona a sua frota na tabela de posicionamento. Então é sorteado um dos jogadores para atacar primeiro, e eles se revezam até o fim do jogo. O ataque consiste de o jogador da vez marcar um local na tabela de ataque, e o seu adversário confirma se ele acertou o tiro em um navio ou na água. Se um navio foi acertado, o seu tipo só é revelado após ele ser afundado. Um navio afunda quando for atingido por completo.
Nesta simulação, um jogador humano enfrentará o computador. Para simplificar a interface, as frotas serão posicionadas aleatoriamente no tabuleiro. Estarão visíveis apenas as tabelas do jogador.
Universidade Federal de Santa Catarina
INE5358 - Programação Radical – 2005/01.
Alunos:
- Gabriel da Silva Beletti - 0023229-7
- Marcos Fagundes Caetano – 00232092
Nome do Jogo: Complemento de dez.
Descrição do Jogo:
O jogo é formado de dois a vinte jogadores e um baralho convencional. Ao iniciar-se uma partida, o jogador deve dizer um número e puxar uma carta , e o somatório dos dois valores deve ser menor ou igual a 10. O jogador que tiver o número resultante mais próximo de dez, vence a rodada. Se o somatório for superior a dez, o jogador é eliminado da partida. Após a jogada de uma participante, a carta é devolvida ao monte e este será embaralhado novamente.
Um jogo é composto por apenas uma rodada. O empate é caracterizado como vitória múltipla. Todos ganham suas medalhas :).
As figuras do baralho possuem valor igual 10.
Atualizado em 26/06/2005.
Nesta Atualizacao foi utilizado o framework disponibilizado pela equipe do jogo caca-niquel;
-- MichelZanini - 04 Jul 2005
ALUNOS: Michel Zanini e Rodrigo Pavezzi
PIG (Porco)
Material: 1 dado de seis faces não viciado. Cada face contem um numero diferente de 1 a 6;
Jogadores: Qualquer número
Descrição: Cada jogador, na sua vez, joga o dado tantas vezes quanto quiser (no maximo 6 vezes), adicionando a cada jogada o número que sair ao seu placar. Mas, se ele tirar 1, perde todos os pontos que conseguiu nessa rodada e passa o dado ao próximo jogador. O jogador pode parar a qualquer momento e passar o dado para o próximo, mantendo assim os pontos marcados na rodada. O primeiro jogador a atingir 100 pontos vence.
Codigo
CodigoJogoDeDadosPig
Framework
Utilizamos o Framework do CacaNiquel:
CodigoFramework
TesteFramework
Jogo de azar, de dois até...digamos...vinte participantes, e um baralho.
Início:
As cartas do baralho são embaralhadas e distribuídas uma a uma, entre os